diff options
Diffstat (limited to 'platform')
59 files changed, 890 insertions, 328 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub index 344ca036de..9f5b8d8387 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -53,14 +53,14 @@ else: print("WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin") if lib_arch_dir != "": - if env["target"] == "release": - lib_type_dir = "release" - elif env["target"] == "release_debug": + if env.debug_features: lib_type_dir = "debug" - else: # debug + elif env.dev_build: lib_type_dir = "dev" + else: # Release + lib_type_dir = "release" - if env["tools"]: + if env.editor_build: lib_tools_dir = "tools/" else: lib_tools_dir = "" diff --git a/platform/android/detect.py b/platform/android/detect.py index 1d9bcdd932..e541aa0373 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -3,6 +3,11 @@ import sys import platform import subprocess +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from SCons import Environment + def is_active(): return True @@ -17,8 +22,6 @@ def can_build(): def get_opts(): - from SCons.Variables import BoolVariable, EnumVariable - return [ ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_env_android_sdk_root()), ("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"), @@ -46,10 +49,7 @@ def get_ndk_version(): def get_flags(): return [ ("arch", "arm64"), # Default for convenience. - ("tools", False), - # Benefits of LTO for Android (size, performance) haven't been clearly established yet. - # So for now we override the default value which may be set when using `production=yes`. - ("lto", "none"), + ("target", "template_debug"), ] @@ -77,7 +77,7 @@ def install_ndk_if_needed(env): env["ANDROID_NDK_ROOT"] = get_android_ndk_root(env) -def configure(env): +def configure(env: "Environment"): # Validate arch. supported_arches = ["x86_32", "x86_64", "arm32", "arm64"] if env["arch"] not in supported_arches: @@ -117,25 +117,11 @@ def configure(env): env.Append(CCFLAGS=target_option) env.Append(LINKFLAGS=target_option) - # Build type - - if env["target"].startswith("release"): - if env["optimize"] == "speed": # optimize for speed (default) - # `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces - # when using `target=release_debug`. - opt = "-O3" if env["target"] == "release" else "-O2" - env.Append(CCFLAGS=[opt, "-fomit-frame-pointer"]) - elif env["optimize"] == "size": # optimize for size - env.Append(CCFLAGS=["-Oz"]) - env.Append(CPPDEFINES=["NDEBUG"]) - env.Append(CCFLAGS=["-ftree-vectorize"]) - elif env["target"] == "debug": - env.Append(LINKFLAGS=["-O0"]) - env.Append(CCFLAGS=["-O0", "-g", "-fno-limit-debug-info"]) - env.Append(CPPDEFINES=["_DEBUG"]) - env.Append(CPPFLAGS=["-UNDEBUG"]) - # LTO + + if env["lto"] == "auto": # LTO benefits for Android (size, performance) haven't been clearly established yet. + env["lto"] = "none" + if env["lto"] != "none": if env["lto"] == "thin": env.Append(CCFLAGS=["-flto=thin"]) @@ -171,7 +157,7 @@ def configure(env): env["AS"] = compiler_path + "/clang" # Disable exceptions and rtti on non-tools (template) builds - if env["tools"]: + if env.editor_build: env.Append(CXXFLAGS=["-frtti"]) elif env["builtin_icu"]: env.Append(CXXFLAGS=["-frtti", "-fno-exceptions"]) diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index e5656bd00b..366bd1c48c 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1669,14 +1669,7 @@ Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExp } void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { - String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); - if (driver == "opengl3") { - r_features->push_back("etc"); - } - // FIXME: Review what texture formats are used for Vulkan. - if (driver == "vulkan") { - r_features->push_back("etc2"); - } + r_features->push_back("etc2"); Vector<String> abis = get_enabled_abis(p_preset); for (int i = 0; i < abis.size(); ++i) { diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index 8d370a31a4..2f53942f76 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -189,9 +189,7 @@ String bool_to_string(bool v) { } String _get_gles_tag() { - bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES3" && - !ProjectSettings::get_singleton()->get("rendering/driver/fallback_to_gles2"); - return min_gles3 ? " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n" : ""; + return " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n"; } String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) { diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index ace7636e6c..d6cd62e9f5 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -42,7 +42,7 @@ String FileAccessAndroid::get_path_absolute() const { return absolute_path; } -Error FileAccessAndroid::_open(const String &p_path, int p_mode_flags) { +Error FileAccessAndroid::open_internal(const String &p_path, int p_mode_flags) { _close(); path_src = p_path; diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index 8d7ade8ead..55f8fbe0f4 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -49,7 +49,7 @@ class FileAccessAndroid : public FileAccess { public: static AAssetManager *asset_manager; - virtual Error _open(const String &p_path, int p_mode_flags) override; // open a file + virtual Error open_internal(const String &p_path, int p_mode_flags) override; // open a file virtual bool is_open() const override; // true when file is open /// returns the path for the current open file diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp index 56561cb616..c2ee3389ae 100644 --- a/platform/android/file_access_filesystem_jandroid.cpp +++ b/platform/android/file_access_filesystem_jandroid.cpp @@ -61,7 +61,7 @@ String FileAccessFilesystemJAndroid::get_path_absolute() const { return absolute_path; } -Error FileAccessFilesystemJAndroid::_open(const String &p_path, int p_mode_flags) { +Error FileAccessFilesystemJAndroid::open_internal(const String &p_path, int p_mode_flags) { if (is_open()) { _close(); } diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h index 76d7db6e3a..815ab36516 100644 --- a/platform/android/file_access_filesystem_jandroid.h +++ b/platform/android/file_access_filesystem_jandroid.h @@ -60,7 +60,7 @@ class FileAccessFilesystemJAndroid : public FileAccess { void _set_eof(bool eof); public: - virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file virtual bool is_open() const override; ///< true when file is open /// returns the path for the current open file diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index a75c69484c..92e5e59496 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -274,11 +274,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC return false; } - final String videoDriver = GodotLib.getGlobal("rendering/driver/driver_name"); - if (videoDriver.equals("vulkan")) { - mRenderView = new GodotVulkanRenderView(activity, this); - } else { + final String renderer = GodotLib.getGlobal("rendering/renderer/rendering_method"); + if (renderer.equals("gl_compatibility")) { mRenderView = new GodotGLRenderView(activity, this, xrMode, use_debug_opengl); + } else { + mRenderView = new GodotVulkanRenderView(activity, this); } View view = mRenderView.getView(); diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h index 9a1a877b6f..24995147d4 100644 --- a/platform/android/java_godot_io_wrapper.h +++ b/platform/android/java_godot_io_wrapper.h @@ -28,9 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// note, swapped java and godot around in the file name so all the java -// wrappers are together - #ifndef JAVA_GODOT_IO_WRAPPER_H #define JAVA_GODOT_IO_WRAPPER_H diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h index a6c7853107..0e96a4e1f3 100644 --- a/platform/android/java_godot_wrapper.h +++ b/platform/android/java_godot_wrapper.h @@ -28,9 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// note, swapped java and godot around in the file name so all the java -// wrappers are together - #ifndef JAVA_GODOT_WRAPPER_H #define JAVA_GODOT_WRAPPER_H diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 142dc54c45..4469c7a0f7 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -44,6 +44,7 @@ #include "net_socket_android.h" #include <dlfcn.h> +#include <sys/system_properties.h> #include "java_godot_io_wrapper.h" #include "java_godot_wrapper.h" @@ -175,6 +176,79 @@ String OS_Android::get_name() const { return "Android"; } +String OS_Android::get_system_property(const char *key) const { + static String value; + char value_str[PROP_VALUE_MAX]; + if (__system_property_get(key, value_str)) { + value = String(value_str); + } + return value; +} + +String OS_Android::get_distribution_name() const { + if (!get_system_property("ro.havoc.version").is_empty()) { + return "Havoc OS"; + } else if (!get_system_property("org.pex.version").is_empty()) { // Putting before "Pixel Experience", because it's derivating from it. + return "Pixel Extended"; + } else if (!get_system_property("org.pixelexperience.version").is_empty()) { + return "Pixel Experience"; + } else if (!get_system_property("ro.potato.version").is_empty()) { + return "POSP"; + } else if (!get_system_property("ro.xtended.version").is_empty()) { + return "Project-Xtended"; + } else if (!get_system_property("org.evolution.version").is_empty()) { + return "Evolution X"; + } else if (!get_system_property("ro.corvus.version").is_empty()) { + return "Corvus-Q"; + } else if (!get_system_property("ro.pa.version").is_empty()) { + return "Paranoid Android"; + } else if (!get_system_property("ro.crdroid.version").is_empty()) { + return "crDroid Android"; + } else if (!get_system_property("ro.syberia.version").is_empty()) { + return "Syberia Project"; + } else if (!get_system_property("ro.arrow.version").is_empty()) { + return "ArrowOS"; + } else if (!get_system_property("ro.lineage.version").is_empty()) { // Putting LineageOS last, just in case any derivative writes to "ro.lineage.version". + return "LineageOS"; + } + + if (!get_system_property("ro.modversion").is_empty()) { // Handles other Android custom ROMs. + return vformat("%s %s", get_name(), "Custom ROM"); + } + + // Handles stock Android. + return get_name(); +} + +String OS_Android::get_version() const { + const Vector<const char *> roms = { "ro.havoc.version", "org.pex.version", "org.pixelexperience.version", + "ro.potato.version", "ro.xtended.version", "org.evolution.version", "ro.corvus.version", "ro.pa.version", + "ro.crdroid.version", "ro.syberia.version", "ro.arrow.version", "ro.lineage.version" }; + for (int i = 0; i < roms.size(); i++) { + static String rom_version = get_system_property(roms[i]); + if (!rom_version.is_empty()) { + return rom_version; + } + } + + static String mod_version = get_system_property("ro.modversion"); // Handles other Android custom ROMs. + if (!mod_version.is_empty()) { + return mod_version; + } + + // Handles stock Android. + static String sdk_version = get_system_property("ro.build.version.sdk_int"); + static String build = get_system_property("ro.build.version.incremental"); + if (!sdk_version.is_empty()) { + if (!build.is_empty()) { + return vformat("%s.%s", sdk_version, build); + } + return sdk_version; + } + + return ""; +} + MainLoop *OS_Android::get_main_loop() const { return main_loop; } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 96c06d715c..d6546a3507 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -65,6 +65,8 @@ private: GodotJavaWrapper *godot_java = nullptr; GodotIOJavaWrapper *godot_io_java = nullptr; + String get_system_property(const char *key) const; + public: static const char *ANDROID_EXEC_PATH; @@ -93,6 +95,8 @@ public: virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual MainLoop *get_main_loop() const override; void main_loop_begin(); diff --git a/platform/ios/detect.py b/platform/ios/detect.py index ed7e714c4e..38e62134b5 100644 --- a/platform/ios/detect.py +++ b/platform/ios/detect.py @@ -2,6 +2,11 @@ import os import sys from methods import detect_darwin_sdk_path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from SCons import Environment + def is_active(): return True @@ -37,15 +42,12 @@ def get_opts(): def get_flags(): return [ ("arch", "arm64"), # Default for convenience. - ("tools", False), + ("target", "template_debug"), ("use_volk", False), - # Disable by default even if production is set, as it makes linking in Xcode - # on exports very slow and that's not what most users expect. - ("lto", "none"), ] -def configure(env): +def configure(env: "Environment"): # Validate arch. supported_arches = ["x86_64", "arm64"] if env["arch"] not in supported_arches: @@ -55,25 +57,11 @@ def configure(env): ) sys.exit() - ## Build type - - if env["target"].startswith("release"): - env.Append(CPPDEFINES=["NDEBUG", ("NS_BLOCK_ASSERTIONS", 1)]) - if env["optimize"] == "speed": # optimize for speed (default) - # `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces - # when using `target=release_debug`. - opt = "-O3" if env["target"] == "release" else "-O2" - env.Append(CCFLAGS=[opt, "-ftree-vectorize", "-fomit-frame-pointer"]) - env.Append(LINKFLAGS=[opt]) - elif env["optimize"] == "size": # optimize for size - env.Append(CCFLAGS=["-Os", "-ftree-vectorize"]) - env.Append(LINKFLAGS=["-Os"]) - - elif env["target"] == "debug": - env.Append(CCFLAGS=["-gdwarf-2", "-O0"]) - env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1)]) - - # LTO + ## LTO + + if env["lto"] == "auto": # Disable by default as it makes linking in Xcode very slow. + env["lto"] = "none" + if env["lto"] != "none": if env["lto"] == "thin": env.Append(CCFLAGS=["-flto=thin"]) @@ -145,12 +133,10 @@ def configure(env): env.Append(ASFLAGS=["-arch", "arm64"]) env.Append(CPPDEFINES=["NEED_LONG_INT"]) - # Disable exceptions on non-tools (template) builds - if not env["tools"]: - if env["ios_exceptions"]: - env.Append(CCFLAGS=["-fexceptions"]) - else: - env.Append(CCFLAGS=["-fno-exceptions"]) + if env["ios_exceptions"]: + env.Append(CCFLAGS=["-fexceptions"]) + else: + env.Append(CCFLAGS=["-fno-exceptions"]) # Temp fix for ABS/MAX/MIN macros in iOS SDK blocking compilation env.Append(CCFLAGS=["-Wno-ambiguous-macro"]) diff --git a/platform/ios/display_layer.mm b/platform/ios/display_layer.mm index 7c83494768..74c760ae9a 100644 --- a/platform/ios/display_layer.mm +++ b/platform/ios/display_layer.mm @@ -89,12 +89,12 @@ // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? - // Create GL ES 2 context - if (GLOBAL_GET("rendering/driver/driver_name") == "opengl3") { - context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - NSLog(@"Setting up an OpenGL ES 2.0 context."); + // Create GL ES 3 context + if (GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility") { + context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; + NSLog(@"Setting up an OpenGL ES 3.0 context."); if (!context) { - NSLog(@"Failed to create OpenGL ES 2.0 context!"); + NSLog(@"Failed to create OpenGL ES 3.0 context!"); return; } } diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index 74d6bc2e97..d3a0f38463 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -62,7 +62,7 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode // Note that we should be checking "opengl3" as the driver, might never enable this seeing OpenGL is deprecated on iOS // We are hardcoding the rendering_driver to "vulkan" down below - if (rendering_driver == "opengl_es") { + if (rendering_driver == "opengl3") { bool gl_initialization_error = false; // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? @@ -163,7 +163,7 @@ Vector<String> DisplayServerIOS::get_rendering_drivers_func() { drivers.push_back("vulkan"); #endif #if defined(GLES3_ENABLED) - drivers.push_back("opengl_es"); + drivers.push_back("opengl3"); #endif return drivers; diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 7aacb2de85..74a57dc614 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -34,7 +34,6 @@ #include "editor/editor_node.h" void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { - String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); // Vulkan and OpenGL ES 3.0 both mandate ETC2 support. r_features->push_back("etc2"); diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm index 9ed219508c..ff90c05b1d 100644 --- a/platform/ios/godot_view.mm +++ b/platform/ios/godot_view.mm @@ -74,7 +74,7 @@ static const float earth_gravity = 9.80665; if ([driverName isEqualToString:@"vulkan"]) { layer = [GodotMetalLayer layer]; - } else if ([driverName isEqualToString:@"opengl_es"]) { + } else if ([driverName isEqualToString:@"opengl3"]) { if (@available(iOS 13, *)) { NSLog(@"OpenGL ES is deprecated on iOS 13"); } diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h index 3b88f53b6a..400040875f 100644 --- a/platform/ios/os_ios.h +++ b/platform/ios/os_ios.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef IOS_ENABLED - #ifndef OS_IOS_H #define OS_IOS_H +#ifdef IOS_ENABLED + #include "drivers/coreaudio/audio_driver_coreaudio.h" #include "drivers/unix/os_unix.h" #include "ios.h" @@ -100,6 +100,8 @@ public: virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override; virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual String get_model_name() const override; virtual Error shell_open(String p_uri) override; @@ -122,6 +124,6 @@ public: void on_focus_in(); }; -#endif // OS_IOS_H +#endif // IOS_ENABLED #endif // OS_IOS_H diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm index b9d186f355..a674498620 100644 --- a/platform/ios/os_ios.mm +++ b/platform/ios/os_ios.mm @@ -240,6 +240,15 @@ String OS_IOS::get_name() const { return "iOS"; } +String OS_IOS::get_distribution_name() const { + return get_name(); +} + +String OS_IOS::get_version() const { + NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion; + return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion); +} + String OS_IOS::get_model_name() const { String model = ios->get_model(); if (model != "") { diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 36644d5f29..dfde0d249c 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -4,6 +4,11 @@ import sys from methods import get_compiler_version, using_gcc from platform_methods import detect_arch +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from SCons import Environment + def is_active(): return True @@ -44,8 +49,6 @@ def get_opts(): BoolVariable("fontconfig", "Detect and use fontconfig for system fonts support", True), BoolVariable("udev", "Use udev for gamepad connection callbacks", True), BoolVariable("x11", "Enable X11 display", True), - BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), - BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False), BoolVariable("touch", "Enable touch events", True), BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False), ] @@ -57,7 +60,7 @@ def get_flags(): ] -def configure(env): +def configure(env: "Environment"): # Validate arch. supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64"] if env["arch"] not in supported_arches: @@ -69,26 +72,9 @@ def configure(env): ## Build type - if env["target"] == "release": - if env["optimize"] == "speed": # optimize for speed (default) - env.Prepend(CCFLAGS=["-O3"]) - elif env["optimize"] == "size": # optimize for size - env.Prepend(CCFLAGS=["-Os"]) - - if env["debug_symbols"]: - env.Prepend(CCFLAGS=["-g2"]) - - elif env["target"] == "release_debug": - if env["optimize"] == "speed": # optimize for speed (default) - env.Prepend(CCFLAGS=["-O2"]) - elif env["optimize"] == "size": # optimize for size - env.Prepend(CCFLAGS=["-Os"]) - - if env["debug_symbols"]: - env.Prepend(CCFLAGS=["-g2"]) - - elif env["target"] == "debug": - env.Prepend(CCFLAGS=["-g3"]) + if env.dev_build: + # This is needed for our crash handler to work properly. + # gdb works fine without it though, so maybe our crash handler could too. env.Append(LINKFLAGS=["-rdynamic"]) # CPU architecture flags. @@ -171,6 +157,10 @@ def configure(env): env.Append(LINKFLAGS=["-fsanitize=memory"]) # LTO + + if env["lto"] == "auto": # Full LTO for production. + env["lto"] = "full" + if env["lto"] != "none": if env["lto"] == "thin": if not env["use_llvm"]: @@ -379,7 +369,7 @@ def configure(env): if env["execinfo"]: env.Append(LIBS=["execinfo"]) - if not env["tools"]: + if not env.editor_build: import subprocess import re diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h index 21ebaead32..7eb7064cc5 100644 --- a/platform/linuxbsd/detect_prime_x11.h +++ b/platform/linuxbsd/detect_prime_x11.h @@ -28,11 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef X11_ENABLED -#if defined(GLES3_ENABLED) +#ifndef DETECT_PRIME_X11_H +#define DETECT_PRIME_X11_H + +#if defined(X11_ENABLED) && defined(GLES3_ENABLED) int detect_prime(); -#endif +#endif // X11_ENABLED && GLES3_ENABLED #endif // DETECT_PRIME_X11_H diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/gl_manager_x11.cpp index 838be2c042..f586c57dda 100644 --- a/platform/linuxbsd/gl_manager_x11.cpp +++ b/platform/linuxbsd/gl_manager_x11.cpp @@ -310,7 +310,7 @@ void GLManager_X11::swap_buffers() { return; } - // On X11, when enabled, transparancy is always active, so clear alpha manually. + // On X11, when enabled, transparency is always active, so clear alpha manually. if (OS::get_singleton()->is_layered_allowed()) { if (!DisplayServer::get_singleton()->window_get_flag(DisplayServer::WINDOW_FLAG_TRANSPARENT, _current_window->window_id)) { glColorMask(false, false, false, true); diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index f0d7b6ede5..f4e94f1a91 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -50,6 +50,7 @@ #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> +#include <sys/utsname.h> #include <unistd.h> #ifdef FONTCONFIG_ENABLED @@ -205,6 +206,42 @@ String OS_LinuxBSD::get_name() const { #endif } +String OS_LinuxBSD::get_systemd_os_release_info_value(const String &key) const { + static String info; + if (info.is_empty()) { + Ref<FileAccess> f = FileAccess::open("/etc/os-release", FileAccess::READ); + if (f.is_valid()) { + while (!f->eof_reached()) { + const String line = f->get_line(); + if (line.find(key) != -1) { + return line.split("=")[1].strip_edges(); + } + } + } + } + return info; +} + +String OS_LinuxBSD::get_distribution_name() const { + static String systemd_name = get_systemd_os_release_info_value("NAME"); // returns a value for systemd users, otherwise an empty string. + if (!systemd_name.is_empty()) { + return systemd_name; + } + struct utsname uts; // returns a decent value for BSD family. + uname(&uts); + return uts.sysname; +} + +String OS_LinuxBSD::get_version() const { + static String systemd_version = get_systemd_os_release_info_value("VERSION"); // returns a value for systemd users, otherwise an empty string. + if (!systemd_version.is_empty()) { + return systemd_version; + } + struct utsname uts; // returns a decent value for BSD family. + uname(&uts); + return uts.version; +} + Error OS_LinuxBSD::shell_open(String p_uri) { Error ok; int err_code; diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index d5b2321316..722d83ba19 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -67,6 +67,8 @@ class OS_LinuxBSD : public OS_Unix { MainLoop *main_loop = nullptr; + String get_systemd_os_release_info_value(const String &key) const; + protected: virtual void initialize() override; virtual void finalize() override; @@ -77,6 +79,8 @@ protected: public: virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual MainLoop *get_main_loop() const override; diff --git a/platform/macos/SCsub b/platform/macos/SCsub index bbd461fba9..7ffb80f70b 100644 --- a/platform/macos/SCsub +++ b/platform/macos/SCsub @@ -12,6 +12,7 @@ files = [ "crash_handler_macos.mm", "macos_terminal_logger.mm", "display_server_macos.mm", + "godot_button_view.mm", "godot_content_view.mm", "godot_window_delegate.mm", "godot_window.mm", diff --git a/platform/macos/detect.py b/platform/macos/detect.py index bcf4776609..511286d52b 100644 --- a/platform/macos/detect.py +++ b/platform/macos/detect.py @@ -3,6 +3,11 @@ import sys from methods import detect_darwin_sdk_path from platform_methods import detect_arch +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from SCons import Environment + def is_active(): return True @@ -27,8 +32,6 @@ def get_opts(): ("MACOS_SDK_PATH", "Path to the macOS SDK", ""), ("vulkan_sdk_path", "Path to the Vulkan SDK", ""), EnumVariable("macports_clang", "Build using Clang from MacPorts", "no", ("no", "5.0", "devel")), - BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), - BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False), BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False), BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False), BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False), @@ -40,9 +43,6 @@ def get_flags(): return [ ("arch", detect_arch()), ("use_volk", False), - # Benefits of LTO for macOS (size, performance) haven't been clearly established yet. - # So for now we override the default value which may be set when using `production=yes`. - ("lto", "none"), ] @@ -77,7 +77,7 @@ def get_mvk_sdk_path(): return os.path.join(os.path.join(dirname, ver_file), "MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/") -def configure(env): +def configure(env: "Environment"): # Validate arch. supported_arches = ["x86_64", "arm64"] if env["arch"] not in supported_arches: @@ -89,27 +89,10 @@ def configure(env): ## Build type - if env["target"] == "release": - if env["optimize"] == "speed": # optimize for speed (default) - env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize"]) - elif env["optimize"] == "size": # optimize for size - env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize"]) + if env["target"] == "template_release": if env["arch"] != "arm64": env.Prepend(CCFLAGS=["-msse2"]) - - if env["debug_symbols"]: - env.Prepend(CCFLAGS=["-g2"]) - - elif env["target"] == "release_debug": - if env["optimize"] == "speed": # optimize for speed (default) - env.Prepend(CCFLAGS=["-O2"]) - elif env["optimize"] == "size": # optimize for size - env.Prepend(CCFLAGS=["-Os"]) - if env["debug_symbols"]: - env.Prepend(CCFLAGS=["-g2"]) - - elif env["target"] == "debug": - env.Prepend(CCFLAGS=["-g3"]) + elif env.dev_build: env.Prepend(LINKFLAGS=["-Xlinker", "-no_deduplicate"]) ## Compiler configuration @@ -170,6 +153,10 @@ def configure(env): env["AS"] = basecmd + "as" # LTO + + if env["lto"] == "auto": # LTO benefits for macOS (size, performance) haven't been clearly established yet. + env["lto"] = "none" + if env["lto"] != "none": if env["lto"] == "thin": env.Append(CCFLAGS=["-flto=thin"]) @@ -178,6 +165,8 @@ def configure(env): env.Append(CCFLAGS=["-flto"]) env.Append(LINKFLAGS=["-flto"]) + # Sanitizers + if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]: env.extra_suffix += ".san" env.Append(CCFLAGS=["-DSANITIZERS_ENABLED"]) diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index da377c9171..e72273a681 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -76,6 +76,7 @@ public: id window_delegate; id window_object; id window_view; + id window_button_view; Vector<Vector2> mpath; @@ -84,6 +85,7 @@ public: Size2i min_size; Size2i max_size; Size2i size; + Vector2i wb_offset = Vector2i(14, 14); NSRect last_frame_rect; @@ -177,6 +179,12 @@ private: IOPMAssertionID screen_keep_on_assertion = kIOPMNullAssertionID; + struct MenuCall { + Variant tag; + Callable callback; + }; + Vector<MenuCall> deferred_menu_calls; + const NSMenu *_get_menu_root(const String &p_menu_root) const; NSMenu *_get_menu_root(const String &p_menu_root); @@ -228,6 +236,7 @@ public: void window_update(WindowID p_window); void window_destroy(WindowID p_window); void window_resize(WindowID p_window, int p_width, int p_height); + void window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled); virtual bool has_feature(Feature p_feature) const override; virtual String get_name() const override; @@ -391,6 +400,7 @@ public: virtual bool window_maximize_on_title_dbl_click() const override; virtual bool window_minimize_on_title_dbl_click() const override; + virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) override; virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const override; virtual Point2i ime_get_selection() const override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 05f89c70aa..1914c5f35d 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -30,6 +30,7 @@ #include "display_server_macos.h" +#include "godot_button_view.h" #include "godot_content_view.h" #include "godot_menu_delegate.h" #include "godot_menu_item.h" @@ -564,11 +565,11 @@ void DisplayServerMacOS::menu_callback(id p_sender) { } if (value->callback != Callable()) { - Variant tag = value->meta; - Variant *tagp = &tag; - Variant ret; - Callable::CallError ce; - value->callback.callp((const Variant **)&tagp, 1, ret, ce); + MenuCall mc; + mc.tag = value->meta; + mc.callback = value->callback; + deferred_menu_calls.push_back(mc); + // Do not run callback from here! If it is opening a new window or calling process_events, it will corrupt OS event queue and crash. } } } @@ -2212,7 +2213,9 @@ void DisplayServerMacOS::show_window(WindowID p_id) { WindowData &wd = windows[p_id]; popup_open(p_id); - if (wd.no_focus || wd.is_popup) { + if ([wd.window_object isMiniaturized]) { + return; + } else if (wd.no_focus || wd.is_popup) { [wd.window_object orderFront:nil]; } else { [wd.window_object makeKeyAndOrderFront:nil]; @@ -2369,6 +2372,10 @@ void DisplayServerMacOS::window_set_position(const Point2i &p_position, WindowID ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if ([wd.window_object isZoomed]) { + return; + } + Point2i position = p_position; // OS X native y-coordinate relative to _get_screens_origin() is negative, // Godot passes a positive value. @@ -2493,6 +2500,10 @@ void DisplayServerMacOS::window_set_size(const Size2i p_size, WindowID p_window) ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if ([wd.window_object isZoomed]) { + return; + } + Size2i size = p_size / screen_get_max_scale(); NSPoint top_left; @@ -2639,27 +2650,59 @@ bool DisplayServerMacOS::window_minimize_on_title_dbl_click() const { return false; } +void DisplayServerMacOS::window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd = windows[p_window]; + wd.wb_offset = p_offset; +} + Vector2i DisplayServerMacOS::window_get_safe_title_margins(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Vector2i()); const WindowData &wd = windows[p_window]; - float max_x = 0.f; - NSButton *cb = [wd.window_object standardWindowButton:NSWindowCloseButton]; - if (cb) { - max_x = MAX(max_x, [cb frame].origin.x + [cb frame].size.width); + if (!wd.window_button_view) { + return Vector2i(); } - NSButton *mb = [wd.window_object standardWindowButton:NSWindowMiniaturizeButton]; - if (mb) { - max_x = MAX(max_x, [mb frame].origin.x + [mb frame].size.width); + + float max_x = wd.wb_offset.x + [wd.window_button_view frame].size.width; + + if ([wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft) { + return Vector2i(0, max_x * screen_get_max_scale()); + } else { + return Vector2i(max_x * screen_get_max_scale(), 0); } - NSButton *zb = [wd.window_object standardWindowButton:NSWindowZoomButton]; - if (zb) { - max_x = MAX(max_x, [zb frame].origin.x + [zb frame].size.width); +} + +void DisplayServerMacOS::window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled) { + if (p_wd.window_button_view) { + [p_wd.window_button_view removeFromSuperview]; + p_wd.window_button_view = nil; } + if (p_enabled) { + float cb_frame = NSMinX([[p_wd.window_object standardWindowButton:NSWindowCloseButton] frame]); + float mb_frame = NSMinX([[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] frame]); + bool is_rtl = ([p_wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft); + + float window_buttons_spacing = (is_rtl) ? (cb_frame - mb_frame) : (mb_frame - cb_frame); - return Vector2i(max_x * screen_get_max_scale(), 0); + [p_wd.window_object setTitleVisibility:NSWindowTitleHidden]; + [[p_wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:YES]; + [[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; + [[p_wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:YES]; + + p_wd.window_button_view = [[GodotButtonView alloc] initWithFrame:NSZeroRect]; + [p_wd.window_button_view initButtons:window_buttons_spacing offset:NSMakePoint(p_wd.wb_offset.x, p_wd.wb_offset.y) rtl:is_rtl]; + [p_wd.window_view addSubview:p_wd.window_button_view]; + } else { + [p_wd.window_object setTitleVisibility:NSWindowTitleVisible]; + [[p_wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:NO]; + [[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:NO]; + [[p_wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:NO]; + } } void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { @@ -2684,14 +2727,21 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win NSRect rect = [wd.window_object frame]; if (p_enabled) { [wd.window_object setTitlebarAppearsTransparent:YES]; - [wd.window_object setTitleVisibility:NSWindowTitleHidden]; [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskFullSizeContentView]; + + if (!wd.fullscreen) { + window_set_custom_window_buttons(wd, true); + } } else { [wd.window_object setTitlebarAppearsTransparent:NO]; - [wd.window_object setTitleVisibility:NSWindowTitleVisible]; [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskFullSizeContentView]; + + if (!wd.fullscreen) { + window_set_custom_window_buttons(wd, false); + } } [wd.window_object setFrame:rect display:YES]; + send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE); } break; case WINDOW_FLAG_BORDERLESS: { // OrderOut prevents a lose focus bug with the window. @@ -2711,7 +2761,9 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win } _update_window_style(wd); if ([wd.window_object isVisible]) { - if (wd.no_focus || wd.is_popup) { + if ([wd.window_object isMiniaturized]) { + return; + } else if (wd.no_focus || wd.is_popup) { [wd.window_object orderFront:nil]; } else { [wd.window_object makeKeyAndOrderFront:nil]; @@ -3228,6 +3280,16 @@ void DisplayServerMacOS::process_events() { [NSApp sendEvent:event]; } + // Process "menu_callback"s. + for (MenuCall &E : deferred_menu_calls) { + Variant tag = E.tag; + Variant *tagp = &tag; + Variant ret; + Callable::CallError ce; + E.callback.callp((const Variant **)&tagp, 1, ret, ce); + } + deferred_menu_calls.clear(); + if (!drop_events) { _process_key_events(); Input::get_singleton()->flush_buffered_events(); diff --git a/platform/macos/export/codesign.h b/platform/macos/export/codesign.h index fea7b117d0..01e97bca81 100644 --- a/platform/macos/export/codesign.h +++ b/platform/macos/export/codesign.h @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef MACOS_CODESIGN_H +#define MACOS_CODESIGN_H + // macOS code signature creation utility. // // Current implementation has the following limitation: @@ -38,9 +41,6 @@ // - Requirements code generator is not implemented (only hard-coded requirements for the ad-hoc signing is supported). // - RFC5652/CMS blob generation is not implemented, supports ad-hoc signing only. -#ifndef MACOS_CODESIGN_H -#define MACOS_CODESIGN_H - #include "core/crypto/crypto_core.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" diff --git a/platform/macos/export/lipo.h b/platform/macos/export/lipo.h index 516ef99860..6378f9899c 100644 --- a/platform/macos/export/lipo.h +++ b/platform/macos/export/lipo.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// Universal / Universal 2 fat binary file creator and extractor. - #ifndef MACOS_LIPO_H #define MACOS_LIPO_H +// Universal / Universal 2 fat binary file creator and extractor. + #include "core/io/file_access.h" #include "core/object/ref_counted.h" #include "modules/modules_enabled.gen.h" // For regex. diff --git a/platform/macos/export/macho.h b/platform/macos/export/macho.h index 7ef0d9067e..0d42a7013f 100644 --- a/platform/macos/export/macho.h +++ b/platform/macos/export/macho.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// Mach-O binary object file format parser and editor. - #ifndef MACOS_MACHO_H #define MACOS_MACHO_H +// Mach-O binary object file format parser and editor. + #include "core/crypto/crypto.h" #include "core/crypto/crypto_core.h" #include "core/io/file_access.h" diff --git a/platform/macos/export/plist.h b/platform/macos/export/plist.h index 79cb928d0a..b3c51a9635 100644 --- a/platform/macos/export/plist.h +++ b/platform/macos/export/plist.h @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// Property list file format (application/x-plist) parser, property list ASN-1 serialization. - #ifndef MACOS_PLIST_H #define MACOS_PLIST_H +// Property list file format (application/x-plist) parser, property list ASN-1 serialization. + #include "core/crypto/crypto_core.h" #include "core/io/file_access.h" #include "modules/modules_enabled.gen.h" // For regex. diff --git a/platform/macos/godot_button_view.h b/platform/macos/godot_button_view.h new file mode 100644 index 0000000000..e7627a9e9b --- /dev/null +++ b/platform/macos/godot_button_view.h @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* godot_button_view.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOT_BUTTON_VIEW_H +#define GODOT_BUTTON_VIEW_H + +#include "servers/display_server.h" + +#import <AppKit/AppKit.h> +#import <Foundation/Foundation.h> + +@interface GodotButtonView : NSView { + NSTrackingArea *tracking_area; + NSPoint offset; + CGFloat spacing; + bool mouse_in_group; + bool rtl; +} + +- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset rtl:(bool)is_rtl; +- (void)displayButtons; + +@end + +#endif // GODOT_BUTTON_VIEW_H diff --git a/platform/macos/godot_button_view.mm b/platform/macos/godot_button_view.mm new file mode 100644 index 0000000000..9106f0b0db --- /dev/null +++ b/platform/macos/godot_button_view.mm @@ -0,0 +1,123 @@ +/*************************************************************************/ +/* godot_button_view.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "godot_button_view.h" + +@implementation GodotButtonView + +- (id)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + + tracking_area = nil; + offset = NSMakePoint(8, 8); + spacing = 20; + mouse_in_group = false; + rtl = false; + + return self; +} + +- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset rtl:(bool)is_rtl { + spacing = button_spacing; + rtl = is_rtl; + + NSButton *close_button = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSWindowStyleMaskTitled]; + [close_button setFrameOrigin:NSMakePoint(rtl ? spacing * 2 : 0, 0)]; + [self addSubview:close_button]; + + NSButton *miniaturize_button = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:NSWindowStyleMaskTitled]; + [miniaturize_button setFrameOrigin:NSMakePoint(spacing, 0)]; + [self addSubview:miniaturize_button]; + + NSButton *zoom_button = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:NSWindowStyleMaskTitled]; + [zoom_button setFrameOrigin:NSMakePoint(rtl ? 0 : spacing * 2, 0)]; + [self addSubview:zoom_button]; + + offset.y = button_offset.y - zoom_button.frame.size.height / 2; + offset.x = button_offset.x - zoom_button.frame.size.width / 2; + + if (rtl) { + [self setFrameSize:NSMakeSize(close_button.frame.origin.x + close_button.frame.size.width, close_button.frame.size.height)]; + } else { + [self setFrameSize:NSMakeSize(zoom_button.frame.origin.x + zoom_button.frame.size.width, zoom_button.frame.size.height)]; + } + [self displayButtons]; +} + +- (void)viewDidMoveToWindow { + if (!self.window) { + return; + } + + if (rtl) { + [self setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; + [self setFrameOrigin:NSMakePoint(self.window.frame.size.width - self.frame.size.width - offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)]; + } else { + [self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; + [self setFrameOrigin:NSMakePoint(offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)]; + } +} + +- (BOOL)_mouseInGroup:(NSButton *)button { + return mouse_in_group; +} + +- (void)updateTrackingAreas { + if (tracking_area != nil) { + [self removeTrackingArea:tracking_area]; + } + + NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect; + tracking_area = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:options owner:self userInfo:nil]; + + [self addTrackingArea:tracking_area]; +} + +- (void)mouseEntered:(NSEvent *)event { + [super mouseEntered:event]; + + mouse_in_group = true; + [self displayButtons]; +} + +- (void)mouseExited:(NSEvent *)event { + [super mouseExited:event]; + + mouse_in_group = false; + [self displayButtons]; +} + +- (void)displayButtons { + for (NSView *subview in self.subviews) { + [subview setNeedsDisplay:YES]; + } +} + +@end diff --git a/platform/macos/godot_window.h b/platform/macos/godot_window.h index 9fc5599e86..d3653fda82 100644 --- a/platform/macos/godot_window.h +++ b/platform/macos/godot_window.h @@ -38,9 +38,11 @@ @interface GodotWindow : NSWindow { DisplayServer::WindowID window_id; + NSTimeInterval anim_duration; } - (void)setWindowID:(DisplayServer::WindowID)wid; +- (void)setAnimDuration:(NSTimeInterval)duration; @end diff --git a/platform/macos/godot_window.mm b/platform/macos/godot_window.mm index e205e7546d..bc51da4f72 100644 --- a/platform/macos/godot_window.mm +++ b/platform/macos/godot_window.mm @@ -37,9 +37,22 @@ - (id)init { self = [super init]; window_id = DisplayServer::INVALID_WINDOW_ID; + anim_duration = -1.0f; return self; } +- (void)setAnimDuration:(NSTimeInterval)duration { + anim_duration = duration; +} + +- (NSTimeInterval)animationResizeTime:(NSRect)newFrame { + if (anim_duration > 0) { + return anim_duration; + } else { + return [super animationResizeTime:newFrame]; + } +} + - (void)setWindowID:(DisplayServerMacOS::WindowID)wid { window_id = wid; } diff --git a/platform/macos/godot_window_delegate.h b/platform/macos/godot_window_delegate.h index 98c226aa2f..01cc13a016 100644 --- a/platform/macos/godot_window_delegate.h +++ b/platform/macos/godot_window_delegate.h @@ -38,6 +38,8 @@ @interface GodotWindowDelegate : NSObject <NSWindowDelegate> { DisplayServer::WindowID window_id; + NSRect old_frame; + NSWindowStyleMask old_style_mask; } - (void)setWindowID:(DisplayServer::WindowID)wid; diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm index e1034c9993..279fd2a359 100644 --- a/platform/macos/godot_window_delegate.mm +++ b/platform/macos/godot_window_delegate.mm @@ -31,6 +31,8 @@ #include "godot_window_delegate.h" #include "display_server_macos.h" +#include "godot_button_view.h" +#include "godot_window.h" @implementation GodotWindowDelegate @@ -68,6 +70,26 @@ ds->window_destroy(window_id); } +- (NSArray<NSWindow *> *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); + if (!ds || !ds->has_window(window_id)) { + return nullptr; + } + + old_frame = [window frame]; + old_style_mask = [window styleMask]; + + NSMutableArray<NSWindow *> *windows = [[NSMutableArray alloc] init]; + [windows addObject:window]; + + return windows; +} + +- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration { + [(GodotWindow *)window setAnimDuration:duration]; + [window setFrame:[[window screen] frame] display:YES animate:YES]; +} + - (void)windowDidEnterFullScreen:(NSNotification *)notification { DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { @@ -76,12 +98,46 @@ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); wd.fullscreen = true; + // Reset window size limits. [wd.window_object setContentMinSize:NSMakeSize(0, 0)]; [wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; + [(GodotWindow *)wd.window_object setAnimDuration:-1.0f]; + + // Reset custom window buttons. + if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) { + ds->window_set_custom_window_buttons(wd, false); + } // Force window resize event. [self windowDidResize:notification]; + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE); +} + +- (NSArray<NSWindow *> *)customWindowsToExitFullScreenForWindow:(NSWindow *)window { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); + if (!ds || !ds->has_window(window_id)) { + return nullptr; + } + + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + + // Restore custom window buttons. + if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) { + ds->window_set_custom_window_buttons(wd, true); + } + + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE); + + NSMutableArray<NSWindow *> *windows = [[NSMutableArray alloc] init]; + [windows addObject:wd.window_object]; + return windows; +} + +- (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration { + [(GodotWindow *)window setAnimDuration:duration]; + [window setStyleMask:old_style_mask]; + [window setFrame:old_frame display:YES animate:YES]; } - (void)windowDidExitFullScreen:(NSNotification *)notification { @@ -93,6 +149,8 @@ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); wd.fullscreen = false; + [(GodotWindow *)wd.window_object setAnimDuration:-1.0f]; + // Set window size limits. const float scale = ds->screen_get_max_scale(); if (wd.min_size != Size2i()) { @@ -219,6 +277,10 @@ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + if (wd.window_button_view) { + [(GodotButtonView *)wd.window_button_view displayButtons]; + } + if (ds->mouse_get_mode() == DisplayServer::MOUSE_MODE_CAPTURED) { const NSRect content_rect = [wd.window_view frame]; NSRect point_in_window_rect = NSMakeRect(content_rect.size.width / 2, content_rect.size.height / 2, 0, 0); @@ -241,6 +303,10 @@ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + if (wd.window_button_view) { + [(GodotButtonView *)wd.window_button_view displayButtons]; + } + ds->release_pressed_events(); ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT); } diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h index 61db99689c..46e7c17ebe 100644 --- a/platform/macos/os_macos.h +++ b/platform/macos/os_macos.h @@ -75,6 +75,8 @@ public: virtual List<String> get_cmdline_platform_args() const override; virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index c250a9d71a..ae8534f6ab 100644 --- a/platform/macos/os_macos.mm +++ b/platform/macos/os_macos.mm @@ -134,6 +134,15 @@ String OS_MacOS::get_name() const { return "macOS"; } +String OS_MacOS::get_distribution_name() const { + return get_name(); +} + +String OS_MacOS::get_version() const { + NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion; + return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion); +} + void OS_MacOS::alert(const String &p_alert, const String &p_title) { NSAlert *window = [[NSAlert alloc] init]; NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()]; diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index 2c5746cb06..64fe5bc4a2 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -3,6 +3,11 @@ import os import sys from platform_methods import detect_arch +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from SCons import Environment + def is_active(): return True @@ -39,7 +44,7 @@ def get_flags(): ] -def configure(env): +def configure(env: "Environment"): # Validate arch. supported_arches = ["x86_32", "x86_64", "arm32"] if env["arch"] not in supported_arches: @@ -83,7 +88,7 @@ def configure(env): env.AppendUnique(CCFLAGS=["/utf-8"]) # ANGLE - angle_root = os.getenv("ANGLE_SRC_PATH") + angle_root = os.environ["ANGLE_SRC_PATH"] env.Prepend(CPPPATH=[angle_root + "/include"]) jobs = str(env.GetOption("num_jobs")) angle_build_cmd = ( @@ -94,7 +99,7 @@ def configure(env): + " /p:Configuration=Release /p:Platform=" ) - if os.path.isfile(str(os.getenv("ANGLE_SRC_PATH")) + "/winrt/10/src/angle.sln"): + if os.path.isfile(f"{angle_root}/winrt/10/src/angle.sln"): env["build_angle"] = True ## Architecture diff --git a/platform/uwp/export/app_packager.cpp b/platform/uwp/export/app_packager.cpp index 87224d38b8..6f8966b9ff 100644 --- a/platform/uwp/export/app_packager.cpp +++ b/platform/uwp/export/app_packager.cpp @@ -301,7 +301,7 @@ Error AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t Vector<uint8_t> file_buffer; // Data for compression - z_stream strm; + z_stream strm{}; Vector<uint8_t> strm_in; strm_in.resize(BLOCK_SIZE); Vector<uint8_t> strm_out; diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 791328964b..8050d299f0 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -444,6 +444,16 @@ String OS_UWP::get_name() const { return "UWP"; } +String OS_UWP::get_distribution_name() const { + return get_name(); +} + +String OS_UWP::get_version() const { + winrt::hstring df_version = VersionInfo().DeviceFamilyVersion(); + static String version = String(winrt::to_string(df_version).c_str()); + return version; +} + OS::DateTime OS_UWP::get_datetime(bool p_utc) const { SYSTEMTIME systemtime; if (p_utc) { diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 7d4224cf74..0c1c4a793a 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -183,6 +183,8 @@ public: virtual MainLoop *get_main_loop() const; virtual String get_name() const; + virtual String get_distribution_name() const; + virtual String get_version() const; virtual DateTime get_datetime(bool p_utc) const; virtual TimeZoneInfo get_time_zone_info() const; diff --git a/platform/web/.eslintrc.engine.js b/platform/web/.eslintrc.engine.js index 78df6d41d9..a76bd46b9e 100644 --- a/platform/web/.eslintrc.engine.js +++ b/platform/web/.eslintrc.engine.js @@ -5,6 +5,7 @@ module.exports = { "globals": { "InternalConfig": true, "Godot": true, + "Features": true, "Preloader": true, }, }; diff --git a/platform/web/SCsub b/platform/web/SCsub index e8d0181ede..013b734be2 100644 --- a/platform/web/SCsub +++ b/platform/web/SCsub @@ -66,6 +66,7 @@ sys_env.Depends(build[0], sys_env["JS_PRE"]) sys_env.Depends(build[0], sys_env["JS_EXTERNS"]) engine = [ + "js/engine/features.js", "js/engine/preloader.js", "js/engine/config.js", "js/engine/engine.js", diff --git a/platform/web/detect.py b/platform/web/detect.py index 08f964db92..08c1ff7b4a 100644 --- a/platform/web/detect.py +++ b/platform/web/detect.py @@ -11,6 +11,10 @@ from emscripten_helpers import ( ) from methods import get_compiler_version from SCons.Util import WhereIs +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from SCons import Environment def is_active(): @@ -47,7 +51,7 @@ def get_opts(): def get_flags(): return [ ("arch", "wasm32"), - ("tools", False), + ("target", "template_debug"), ("builtin_pcre2_with_jit", False), ("vulkan", False), # Use -Os to prioritize optimizing for reduced file size. This is @@ -60,7 +64,7 @@ def get_flags(): ] -def configure(env): +def configure(env: "Environment"): # Validate arch. supported_arches = ["wasm32"] if env["arch"] not in supported_arches: @@ -77,26 +81,17 @@ def configure(env): sys.exit(255) ## Build type - if env["target"].startswith("release"): - 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. - env.Append(LINKFLAGS=["--profiling-funcs"]) - else: # "debug" - env.Append(CCFLAGS=["-O1", "-g"]) - env.Append(LINKFLAGS=["-O1", "-g"]) + + if env.debug_features: + # Retain function names for backtraces at the cost of file size. + env.Append(LINKFLAGS=["--profiling-funcs"]) + else: env["use_assertions"] = True if env["use_assertions"]: env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"]) - if env["tools"]: + if env.editor_build: if env["initial_memory"] < 64: print('Note: Forcing "initial_memory=64" as it is required for the web editor.') env["initial_memory"] = 64 @@ -109,6 +104,10 @@ def configure(env): env["ENV"] = os.environ # LTO + + if env["lto"] == "auto": # Full LTO for production. + env["lto"] = "full" + if env["lto"] != "none": if env["lto"] == "thin": env.Append(CCFLAGS=["-flto=thin"]) diff --git a/platform/web/emscripten_helpers.py b/platform/web/emscripten_helpers.py index 6045bc6fbd..ec33397842 100644 --- a/platform/web/emscripten_helpers.py +++ b/platform/web/emscripten_helpers.py @@ -38,7 +38,7 @@ def create_engine_file(env, target, source, externs): def create_template_zip(env, js, wasm, worker, side): - binary_name = "godot.tools" if env["tools"] else "godot" + binary_name = "godot.editor" if env.editor_build else "godot" zip_dir = env.Dir("#bin/.web_zip") in_files = [ js, @@ -58,19 +58,19 @@ def create_template_zip(env, js, wasm, worker, side): out_files.append(zip_dir.File(binary_name + ".side.wasm")) service_worker = "#misc/dist/html/service-worker.js" - if env["tools"]: + if env.editor_build: # HTML html = "#misc/dist/html/editor.html" cache = [ - "godot.tools.html", + "godot.editor.html", "offline.html", - "godot.tools.js", - "godot.tools.worker.js", - "godot.tools.audio.worklet.js", + "godot.editor.js", + "godot.editor.worker.js", + "godot.editor.audio.worklet.js", "logo.svg", "favicon.png", ] - opt_cache = ["godot.tools.wasm"] + opt_cache = ["godot.editor.wasm"] subst_dict = { "@GODOT_VERSION@": get_build_version(), "@GODOT_NAME@": "GodotEngine", diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index 306453c1eb..1c327fe4b2 100644 --- a/platform/web/export/export_plugin.cpp +++ b/platform/web/export/export_plugin.cpp @@ -307,13 +307,7 @@ void EditorExportPlatformWeb::get_preset_features(const Ref<EditorExportPreset> } if (p_preset->get("vram_texture_compression/for_mobile")) { - String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); - if (driver == "opengl3") { - r_features->push_back("etc"); - } else if (driver == "vulkan") { - // FIXME: Review if this is correct. - r_features->push_back("etc2"); - } + r_features->push_back("etc2"); } r_features->push_back("wasm32"); } diff --git a/platform/web/js/engine/engine.js b/platform/web/js/engine/engine.js index 6f0d51b2be..9227aa1f05 100644 --- a/platform/web/js/engine/engine.js +++ b/platform/web/js/engine/engine.js @@ -61,20 +61,6 @@ const Engine = (function () { }; /** - * Check whether WebGL is available. Optionally, specify a particular version of WebGL to check for. - * - * @param {number=} [majorVersion=1] The major WebGL version to check for. - * @returns {boolean} If the given major version of WebGL is available. - * @function Engine.isWebGLAvailable - */ - Engine.isWebGLAvailable = function (majorVersion = 1) { - try { - return !!document.createElement('canvas').getContext(['webgl', 'webgl2'][majorVersion - 1]); - } catch (e) { /* Not available */ } - return false; - }; - - /** * Safe Engine constructor, creates a new prototype for every new instance to avoid prototype pollution. * @ignore * @constructor @@ -265,14 +251,21 @@ const Engine = (function () { // Also expose static methods as instance methods Engine.prototype['load'] = Engine.load; Engine.prototype['unload'] = Engine.unload; - Engine.prototype['isWebGLAvailable'] = Engine.isWebGLAvailable; return new Engine(initConfig); } // Closure compiler exported static methods. SafeEngine['load'] = Engine.load; SafeEngine['unload'] = Engine.unload; - SafeEngine['isWebGLAvailable'] = Engine.isWebGLAvailable; + + // Feature-detection utilities. + SafeEngine['isWebGLAvailable'] = Features.isWebGLAvailable; + SafeEngine['isFetchAvailable'] = Features.isFetchAvailable; + SafeEngine['isSecureContext'] = Features.isSecureContext; + SafeEngine['isCrossOriginIsolated'] = Features.isCrossOriginIsolated; + SafeEngine['isSharedArrayBufferAvailable'] = Features.isSharedArrayBufferAvailable; + SafeEngine['isAudioWorkletAvailable'] = Features.isAudioWorkletAvailable; + SafeEngine['getMissingFeatures'] = Features.getMissingFeatures; return SafeEngine; }()); diff --git a/platform/web/js/engine/features.js b/platform/web/js/engine/features.js new file mode 100644 index 0000000000..f91a4eff81 --- /dev/null +++ b/platform/web/js/engine/features.js @@ -0,0 +1,96 @@ +const Features = { // eslint-disable-line no-unused-vars + /** + * Check whether WebGL is available. Optionally, specify a particular version of WebGL to check for. + * + * @param {number=} [majorVersion=1] The major WebGL version to check for. + * @returns {boolean} If the given major version of WebGL is available. + * @function Engine.isWebGLAvailable + */ + isWebGLAvailable: function (majorVersion = 1) { + try { + return !!document.createElement('canvas').getContext(['webgl', 'webgl2'][majorVersion - 1]); + } catch (e) { /* Not available */ } + return false; + }, + + /** + * Check whether the Fetch API available and supports streaming responses. + * + * @returns {boolean} If the Fetch API is available and supports streaming responses. + * @function Engine.isFetchAvailable + */ + isFetchAvailable: function () { + return 'fetch' in window && 'Response' in window && 'body' in window.Response.prototype; + }, + + /** + * Check whether the engine is running in a Secure Context. + * + * @returns {boolean} If the engine is running in a Secure Context. + * @function Engine.isSecureContext + */ + isSecureContext: function () { + return window['isSecureContext'] === true; + }, + + /** + * Check whether the engine is cross origin isolated. + * This value is dependent on Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers sent by the server. + * + * @returns {boolean} If the engine is running in a Secure Context. + * @function Engine.isSecureContext + */ + isCrossOriginIsolated: function () { + return window['crossOriginIsolated'] === true; + }, + + /** + * Check whether SharedBufferArray is available. + * + * Most browsers require the page to be running in a secure context, and the + * the server to provide specific CORS headers for SharedArrayBuffer to be available. + * + * @returns {boolean} If SharedArrayBuffer is available. + * @function Engine.isSharedArrayBufferAvailable + */ + isSharedArrayBufferAvailable: function () { + return 'SharedArrayBuffer' in window; + }, + + /** + * Check whether the AudioContext supports AudioWorkletNodes. + * + * @returns {boolean} If AudioWorkletNode is available. + * @function Engine.isAudioWorkletAvailable + */ + isAudioWorkletAvailable: function () { + return 'AudioContext' in window && 'audioWorklet' in AudioContext.prototype; + }, + + /** + * Return an array of missing required features (as string). + * + * @returns {Array<string>} A list of human-readable missing features. + * @function Engine.getMissingFeatures + */ + getMissingFeatures: function () { + const missing = []; + if (!Features.isWebGLAvailable(2)) { + missing.push('WebGL2'); + } + if (!Features.isFetchAvailable()) { + missing.push('Fetch'); + } + if (!Features.isSecureContext()) { + missing.push('Secure Context'); + } + if (!Features.isCrossOriginIsolated()) { + missing.push('Cross Origin Isolation'); + } + if (!Features.isSharedArrayBufferAvailable()) { + missing.push('SharedArrayBuffer'); + } + // Audio is normally optional since we have a dummy fallback. + return missing; + }, +}; diff --git a/platform/web/package.json b/platform/web/package.json index a57205415a..0a8d9e4334 100644 --- a/platform/web/package.json +++ b/platform/web/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "description": "Development and linting setup for Godot's Web platform code", "scripts": { - "docs": "jsdoc --template js/jsdoc2rst/ js/engine/engine.js js/engine/config.js --destination ''", + "docs": "jsdoc --template js/jsdoc2rst/ js/engine/engine.js js/engine/config.js js/engine/features.js --destination ''", "lint": "npm run lint:engine && npm run lint:libs && npm run lint:modules && npm run lint:tools", "lint:engine": "eslint \"js/engine/*.js\" --no-eslintrc -c .eslintrc.engine.js", "lint:libs": "eslint \"js/libs/*.js\" --no-eslintrc -c .eslintrc.libs.js", diff --git a/platform/windows/detect.py b/platform/windows/detect.py index e6e1874fc0..a5d8d0344b 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -4,6 +4,11 @@ import subprocess import sys from platform_methods import detect_arch +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from SCons import Environment + # To match other platforms STACK_SIZE = 8388608 @@ -173,17 +178,7 @@ def get_opts(): "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601", ), - BoolVariable( - "debug_symbols", - "Add debugging symbols to release/release_debug builds", - True, - ), EnumVariable("windows_subsystem", "Windows subsystem", "gui", ("gui", "console")), - BoolVariable( - "separate_debug_symbols", - "Create a separate file containing debugging symbols", - False, - ), ( "msvc_version", "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", @@ -330,32 +325,11 @@ def setup_mingw(env): def configure_msvc(env, vcvars_msvc_config): """Configure env to work with MSVC""" - # Build type - if env["target"] == "release": - if env["optimize"] == "speed": # optimize for speed (default) - env.Append(CCFLAGS=["/O2"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - elif env["optimize"] == "size": # optimize for size - env.Append(CCFLAGS=["/O1"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"]) - - elif env["target"] == "release_debug": - if env["optimize"] == "speed": # optimize for speed (default) - env.Append(CCFLAGS=["/O2"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - elif env["optimize"] == "size": # optimize for size - env.Append(CCFLAGS=["/O1"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - - elif env["target"] == "debug": - env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"]) - # Allow big objects. Only needed for debug, see MinGW branch for rationale. - env.Append(LINKFLAGS=["/DEBUG"]) + ## Build type - if env["debug_symbols"]: - env.AppendUnique(CCFLAGS=["/Zi", "/FS"]) - env.AppendUnique(LINKFLAGS=["/DEBUG"]) + # TODO: Re-evaluate the need for this / streamline with common config. + if env["target"] == "template_release": + env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"]) if env["windows_subsystem"] == "gui": env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"]) @@ -448,6 +422,9 @@ def configure_msvc(env, vcvars_msvc_config): ## LTO + if env["lto"] == "auto": # No LTO by default for MSVC, doesn't help. + env["lto"] = "none" + if env["lto"] != "none": if env["lto"] == "thin": print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.") @@ -489,31 +466,10 @@ def configure_mingw(env): if env["use_llvm"] and not try_cmd("clang --version", env["mingw_prefix"], env["arch"]): env["use_llvm"] = False - if env["target"] == "release": + # TODO: Re-evaluate the need for this / streamline with common config. + if env["target"] == "template_release": env.Append(CCFLAGS=["-msse2"]) - - if env["optimize"] == "speed": # optimize for speed (default) - if env["arch"] == "x86_32": - env.Append(CCFLAGS=["-O2"]) - else: - env.Append(CCFLAGS=["-O3"]) - else: # optimize for size - env.Prepend(CCFLAGS=["-Os"]) - - if env["debug_symbols"]: - env.Prepend(CCFLAGS=["-g2"]) - - elif env["target"] == "release_debug": - env.Append(CCFLAGS=["-O2"]) - if env["debug_symbols"]: - env.Prepend(CCFLAGS=["-g2"]) - if env["optimize"] == "speed": # optimize for speed (default) - env.Append(CCFLAGS=["-O2"]) - else: # optimize for size - env.Prepend(CCFLAGS=["-Os"]) - - elif env["target"] == "debug": - env.Append(CCFLAGS=["-g3"]) + elif env.dev_build: # Allow big objects. It's supposed not to have drawbacks but seems to break # GCC LTO, so enabling for debug builds only (which are not built with LTO # and are the only ones with too big objects). @@ -564,6 +520,11 @@ def configure_mingw(env): if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]): env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib" + ## LTO + + if env["lto"] == "auto": # Full LTO for production with MinGW. + env["lto"] = "full" + if env["lto"] != "none": if env["lto"] == "thin": if not env["use_llvm"]: @@ -632,7 +593,7 @@ def configure_mingw(env): env.Append(BUILDERS={"RES": env.Builder(action=build_res_file, suffix=".o", src_suffix=".rc")}) -def configure(env): +def configure(env: "Environment"): # Validate arch. supported_arches = ["x86_32", "x86_64", "arm32", "arm64"] if env["arch"] not in supported_arches: diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 4553f31480..77b20dd924 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -685,7 +685,13 @@ void DisplayServerWindows::show_window(WindowID p_id) { _update_window_style(p_id); } - if (wd.no_focus || wd.is_popup) { + if (wd.maximized) { + ShowWindow(wd.hWnd, SW_SHOWMAXIMIZED); + SetForegroundWindow(wd.hWnd); // Slightly higher priority. + SetFocus(wd.hWnd); // Set keyboard focus. + } else if (wd.minimized) { + ShowWindow(wd.hWnd, SW_SHOWMINIMIZED); + } else if (wd.no_focus || wd.is_popup) { // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow ShowWindow(wd.hWnd, SW_SHOWNA); } else { @@ -926,7 +932,7 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; - if (wd.fullscreen) { + if (wd.fullscreen || wd.maximized) { return; } @@ -1059,6 +1065,10 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if (wd.fullscreen || wd.maximized) { + return; + } + int w = p_size.width; int h = p_size.height; @@ -1076,10 +1086,6 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo } #endif - if (wd.fullscreen) { - return; - } - RECT rect; GetWindowRect(wd.hWnd, &rect); @@ -2548,24 +2554,27 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { PACKET packet; if (wintab_WTPacket(windows[window_id].wtctx, wParam, &packet)) { - float pressure = float(packet.pkNormalPressure - windows[window_id].min_pressure) / float(windows[window_id].max_pressure - windows[window_id].min_pressure); - windows[window_id].last_pressure = pressure; + POINT coords; + GetCursorPos(&coords); + ScreenToClient(windows[window_id].hWnd, &coords); + windows[window_id].last_pressure_update = 0; + float pressure = float(packet.pkNormalPressure - windows[window_id].min_pressure) / float(windows[window_id].max_pressure - windows[window_id].min_pressure); double azim = (packet.pkOrientation.orAzimuth / 10.0f) * (Math_PI / 180); double alt = Math::tan((Math::abs(packet.pkOrientation.orAltitude / 10.0f)) * (Math_PI / 180)); + bool inverted = packet.pkStatus & TPS_INVERT; - if (windows[window_id].tilt_supported) { - windows[window_id].last_tilt = Vector2(Math::atan(Math::sin(azim) / alt), Math::atan(Math::cos(azim) / alt)); - } else { - windows[window_id].last_tilt = Vector2(); - } + Vector2 tilt = (windows[window_id].tilt_supported) ? Vector2(Math::atan(Math::sin(azim) / alt), Math::atan(Math::cos(azim) / alt)) : Vector2(); - windows[window_id].last_pen_inverted = packet.pkStatus & TPS_INVERT; + // Nothing changed, ignore event. + if (!old_invalid && coords.x == old_x && coords.y == old_y && windows[window_id].last_pressure == pressure && windows[window_id].last_tilt == tilt && windows[window_id].last_pen_inverted == inverted) { + break; + } - POINT coords; - GetCursorPos(&coords); - ScreenToClient(windows[window_id].hWnd, &coords); + windows[window_id].last_pressure = pressure; + windows[window_id].last_tilt = tilt; + windows[window_id].last_pen_inverted = inverted; // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode. if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) { @@ -3346,7 +3355,7 @@ void DisplayServerWindows::_process_key_events() { k->set_ctrl_pressed(ke.control); k->set_meta_pressed(ke.meta); k->set_pressed(true); - k->set_keycode((Key)KeyMappingWindows::get_keysym(ke.wParam)); + k->set_keycode((Key)KeyMappingWindows::get_keysym(MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK))); k->set_physical_keycode((Key)(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)))); k->set_unicode(unicode); if (k->get_unicode() && gr_mem) { @@ -3599,6 +3608,16 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, wd.wtctx = 0; } + if (p_mode == WINDOW_MODE_MAXIMIZED) { + wd.maximized = true; + wd.minimized = false; + } + + if (p_mode == WINDOW_MODE_MINIMIZED) { + wd.maximized = false; + wd.minimized = true; + } + wd.last_pressure = 0; wd.last_pressure_update = 0; wd.last_tilt = Vector2(); diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index cdd1c14978..36b0919185 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -32,6 +32,38 @@ </Expand> </Type> + <Type Name="HashMap<*,*>"> + <Expand> + <Item Name="[size]">num_elements</Item> + <LinkedListItems> + <Size>num_elements</Size> + <HeadPointer>head_element</HeadPointer> + <NextPointer>next</NextPointer> + <ValueNode>data</ValueNode> + </LinkedListItems> + </Expand> + </Type> + + <Type Name="VMap<*,*>"> + <Expand> + <Item Condition="_cowdata._ptr" Name="[size]">*(reinterpret_cast<int*>(_cowdata._ptr) - 1)</Item> + <ArrayItems Condition="_cowdata._ptr"> + <Size>*(reinterpret_cast<int*>(_cowdata._ptr) - 1)</Size> + <ValuePointer>reinterpret_cast<VMap<$T1,$T2>::Pair*>(_cowdata._ptr)</ValuePointer> + </ArrayItems> + </Expand> + </Type> + + <Type Name="VMap<Callable,*>::Pair"> + <DisplayString Condition="dynamic_cast<CallableCustomMethodPointerBase*>(key.custom)">{dynamic_cast<CallableCustomMethodPointerBase*>(key.custom)->text}</DisplayString> + </Type> + + <!-- requires PR 64364 + <Type Name="GDScriptThreadContext"> + <DisplayString Condition="_is_main == true">main thread {_debug_thread_id}</DisplayString> + </Type> + --> + <Type Name="Variant"> <DisplayString Condition="type == Variant::NIL">nil</DisplayString> <DisplayString Condition="type == Variant::BOOL">{_data._bool}</DisplayString> @@ -55,15 +87,17 @@ <DisplayString Condition="type == Variant::OBJECT">{*(Object *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::DICTIONARY">{*(Dictionary *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_BYTE_ARRAY">{*(PackedByteArray *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_INT32_ARRAY">{*(PackedInt32Array *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_BYTE_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<unsigned char>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_INT32_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<int>*>(_data.packed_array)->array}</DisplayString> + <!-- broken, will show incorrect data <DisplayString Condition="type == Variant::PACKED_INT64_ARRAY">{*(PackedInt64Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_FLOAT32_ARRAY">{*(PackedFloat32Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_FLOAT64_ARRAY">{*(PackedFloat64Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_STRING_ARRAY">{*(PackedStringArray *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_VECTOR2_ARRAY">{*(PackedVector2Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_VECTOR3_ARRAY">{*(PackedVector3Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::PACKED_COLOR_ARRAY">{*(PackedColorArray *)_data._mem}</DisplayString> + --> + <DisplayString Condition="type == Variant::PACKED_FLOAT32_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<float>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_FLOAT64_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<double>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_STRING_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<String>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_VECTOR2_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<Vector2>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_VECTOR3_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<Vector3>*>(_data.packed_array)->array}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_COLOR_ARRAY">{reinterpret_cast<const Variant::PackedArrayRef<Color>*>(_data.packed_array)->array}</DisplayString> <StringView Condition="type == Variant::STRING && ((String *)(_data._mem))->_cowdata._ptr">((String *)(_data._mem))->_cowdata._ptr,s32</StringView> @@ -87,7 +121,7 @@ <Item Name="[value]" Condition="type == Variant::OBJECT">*(Object *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::DICTIONARY">*(Dictionary *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::ARRAY">*(Array *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::PACKED_BYTE_ARRAY">*(PackedByteArray *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_BYTE_ARRAY">reinterpret_cast<const Variant::PackedArrayRef<unsigned char>*>(_data.packed_array)->array</Item> <Item Name="[value]" Condition="type == Variant::PACKED_INT32_ARRAY">*(PackedInt32Array *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::PACKED_INT64_ARRAY">*(PackedInt64Array *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::PACKED_FLOAT32_ARRAY">*(PackedFloat32Array *)_data._mem</Item> @@ -105,6 +139,14 @@ <StringView Condition="_cowdata._ptr != 0">_cowdata._ptr,s32</StringView> </Type> + <Type Name="godot::String"> + <DisplayString>{*reinterpret_cast<void**>(opaque),s32}</DisplayString> + <Expand> + <Item Name="opaque_ptr">*reinterpret_cast<void**>(opaque)</Item> + <Item Name="string">*reinterpret_cast<void**>(opaque),s32</Item> + </Expand> + </Type> + <Type Name="StringName"> <DisplayString Condition="_data && _data->cname">{_data->cname}</DisplayString> <DisplayString Condition="_data && !_data->cname">{_data->name,s32}</DisplayString> @@ -113,6 +155,22 @@ <StringView Condition="_data && !_data->cname">_data->name,s32</StringView> </Type> + <!-- can't cast the opaque to ::StringName because Natvis does not support global namespace specifier? --> + <Type Name="godot::StringName"> + <DisplayString Condition="(*reinterpret_cast<const char***>(opaque))[1]">{(*reinterpret_cast<const char***>(opaque))[1],s8}</DisplayString> + <DisplayString Condition="!(*reinterpret_cast<const char***>(opaque))[1]">{(*reinterpret_cast<const char***>(opaque))[2],s32}</DisplayString> + <Expand> + <Item Name="opaque_ptr">*reinterpret_cast<void**>(opaque)</Item> + <Item Name="&cname">(*reinterpret_cast<const char***>(opaque))+1</Item> + <Item Name="cname">(*reinterpret_cast<const char***>(opaque))[1],s8</Item> + </Expand> + </Type> + + <Type Name="Object::SignalData"> + <DisplayString Condition="user.name._cowdata._ptr">"{user.name}" {slot_map}</DisplayString> + <DisplayString Condition="!user.name._cowdata._ptr">"{slot_map}</DisplayString> + </Type> + <Type Name="Vector2"> <DisplayString>{{{x},{y}}}</DisplayString> <Expand> @@ -149,12 +207,4 @@ <Item Name="alpha">a</Item> </Expand> </Type> - - <Type Name="Node" Inheritable="false"> - <Expand> - <Item Name="Object">(Object*)this</Item> - <Item Name="class_name">(StringName*)(((char*)this) + sizeof(Object))</Item> - <Item Name="data">(Node::Data*)(((char*)this) + sizeof(Object) + sizeof(StringName))</Item> - </Expand> - </Type> </AutoVisualizer> diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp index 72920d2816..13602f7cbc 100644 --- a/platform/windows/godot_windows.cpp +++ b/platform/windows/godot_windows.cpp @@ -87,7 +87,8 @@ CommandLineToArgvA( i = 0; j = 0; - while ((a = CmdLine[i])) { + a = CmdLine[i]; + while (a) { if (in_QM) { if (a == '\"') { in_QM = FALSE; @@ -130,6 +131,7 @@ CommandLineToArgvA( } } i++; + a = CmdLine[i]; } _argv[j] = '\0'; argv[argc] = nullptr; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 2c268ff3d5..1978ec5ab6 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -290,6 +290,24 @@ String OS_Windows::get_name() const { return "Windows"; } +String OS_Windows::get_distribution_name() const { + return get_name(); +} + +String OS_Windows::get_version() const { + typedef LONG NTSTATUS, *PNTSTATUS; + typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion"); + if (version_ptr != nullptr) { + RTL_OSVERSIONINFOW fow = { 0 }; + fow.dwOSVersionInfoSize = sizeof(fow); + if (version_ptr(&fow) == 0x00000000) { + return vformat("%d.%d.%d", (int64_t)fow.dwMajorVersion, (int64_t)fow.dwMinorVersion, (int64_t)fow.dwBuildNumber); + } + } + return ""; +} + OS::DateTime OS_Windows::get_datetime(bool p_utc) const { SYSTEMTIME systemtime; if (p_utc) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 53451b780e..491de2266f 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -143,6 +143,8 @@ public: virtual MainLoop *get_main_loop() const override; virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; virtual void initialize_joypads() override {} |