summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/main.cpp692
-rw-r--r--main/main.h11
-rw-r--r--main/performance.cpp9
-rw-r--r--main/performance.h6
4 files changed, 550 insertions, 168 deletions
diff --git a/main/main.cpp b/main/main.cpp
index bfb0eacdfc..8d5c4af57f 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -31,10 +31,12 @@
#include "main.h"
#include "core/config/project_settings.h"
+#include "core/core_globals.h"
#include "core/core_string_names.h"
#include "core/crypto/crypto.h"
#include "core/debugger/engine_debugger.h"
#include "core/extension/extension_api_dump.h"
+#include "core/extension/gdnative_interface_dump.gen.h"
#include "core/extension/native_extension_manager.h"
#include "core/input/input.h"
#include "core/input/input_map.h"
@@ -62,6 +64,7 @@
#include "scene/main/window.h"
#include "scene/register_scene_types.h"
#include "scene/resources/packed_scene.h"
+#include "scene/theme/theme_db.h"
#include "servers/audio_server.h"
#include "servers/camera_server.h"
#include "servers/display_server.h"
@@ -124,10 +127,13 @@ static RenderingServer *rendering_server = nullptr;
static CameraServer *camera_server = nullptr;
static XRServer *xr_server = nullptr;
static TextServerManager *tsman = nullptr;
+static PhysicsServer3DManager *physics_server_3d_manager = nullptr;
static PhysicsServer3D *physics_server_3d = nullptr;
+static PhysicsServer2DManager *physics_server_2d_manager = nullptr;
static PhysicsServer2D *physics_server_2d = nullptr;
static NavigationServer3D *navigation_server_3d = nullptr;
static NavigationServer2D *navigation_server_2d = nullptr;
+static ThemeDB *theme_db = nullptr;
// We error out if setup2() doesn't turn this true
static bool _start_success = false;
@@ -136,23 +142,32 @@ static bool _start_success = false;
String tablet_driver = "";
String text_driver = "";
String rendering_driver = "";
+String rendering_method = "";
static int text_driver_idx = -1;
static int display_driver_idx = -1;
static int audio_driver_idx = -1;
// Engine config/tools
+static bool single_window = false;
static bool editor = false;
static bool project_manager = false;
static bool cmdline_tool = false;
static String locale;
static bool show_help = false;
static bool auto_quit = false;
-static OS::ProcessID allow_focus_steal_pid = 0;
+static OS::ProcessID editor_pid = 0;
#ifdef TOOLS_ENABLED
+static bool found_project = false;
static bool auto_build_solutions = false;
static String debug_server_uri;
+static int converter_max_kb_file = 4 * 1024; // 4MB
+static int converter_max_line_length = 100000;
+
+HashMap<Main::CLIScope, Vector<String>> forwardable_cli_arguments;
#endif
+bool use_startup_benchmark = false;
+String startup_benchmark_file;
// Display
@@ -160,7 +175,7 @@ static DisplayServer::WindowMode window_mode = DisplayServer::WINDOW_MODE_WINDOW
static DisplayServer::ScreenOrientation window_orientation = DisplayServer::SCREEN_LANDSCAPE;
static DisplayServer::VSyncMode window_vsync_mode = DisplayServer::VSYNC_ENABLED;
static uint32_t window_flags = 0;
-static Size2i window_size = Size2i(1024, 600);
+static Size2i window_size = Size2i(1152, 648);
static int init_screen = -1;
static bool init_fullscreen = false;
@@ -175,16 +190,17 @@ static Vector2 init_custom_pos;
static bool use_debug_profiler = false;
#ifdef DEBUG_ENABLED
static bool debug_collisions = false;
+static bool debug_paths = false;
static bool debug_navigation = false;
#endif
static int frame_delay = 0;
static bool disable_render_loop = false;
static int fixed_fps = -1;
-static String write_movie_path;
static MovieWriter *movie_writer = nullptr;
static bool disable_vsync = false;
static bool print_fps = false;
#ifdef TOOLS_ENABLED
+static bool dump_gdnative_interface = false;
static bool dump_extension_api = false;
#endif
bool profile_gpu = false;
@@ -195,6 +211,12 @@ bool Main::is_cmdline_tool() {
return cmdline_tool;
}
+#ifdef TOOLS_ENABLED
+const Vector<String> &Main::get_forwardable_cli_arguments(Main::CLIScope p_scope) {
+ return forwardable_cli_arguments[p_scope];
+}
+#endif
+
static String unescape_cmdline(const String &p_str) {
return p_str.replace("%20", " ");
}
@@ -207,25 +229,24 @@ static String get_full_version_string() {
return String(VERSION_FULL_BUILD) + hash;
}
-// FIXME: Could maybe be moved to PhysicsServer3DManager and PhysicsServer2DManager directly
-// to have less code in main.cpp.
+// FIXME: Could maybe be moved to have less code in main.cpp.
void initialize_physics() {
/// 3D Physics Server
- physics_server_3d = PhysicsServer3DManager::new_server(
- ProjectSettings::get_singleton()->get(PhysicsServer3DManager::setting_property_name));
+ physics_server_3d = PhysicsServer3DManager::get_singleton()->new_server(
+ GLOBAL_GET(PhysicsServer3DManager::setting_property_name));
if (!physics_server_3d) {
// Physics server not found, Use the default physics
- physics_server_3d = PhysicsServer3DManager::new_default_server();
+ physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
}
ERR_FAIL_COND(!physics_server_3d);
physics_server_3d->init();
- /// 2D Physics server
- physics_server_2d = PhysicsServer2DManager::new_server(
- ProjectSettings::get_singleton()->get(PhysicsServer2DManager::setting_property_name));
+ // 2D Physics server
+ physics_server_2d = PhysicsServer2DManager::get_singleton()->new_server(
+ GLOBAL_GET(PhysicsServer2DManager::get_singleton()->setting_property_name));
if (!physics_server_2d) {
// Physics server not found, Use the default physics
- physics_server_2d = PhysicsServer2DManager::new_default_server();
+ physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
}
ERR_FAIL_COND(!physics_server_2d);
physics_server_2d->init();
@@ -261,6 +282,16 @@ void finalize_navigation_server() {
navigation_server_2d = nullptr;
}
+void initialize_theme_db() {
+ theme_db = memnew(ThemeDB);
+ theme_db->initialize_theme();
+}
+
+void finalize_theme_db() {
+ memdelete(theme_db);
+ theme_db = nullptr;
+}
+
//#define DEBUG_INIT
#ifdef DEBUG_INIT
#define MAIN_PRINT(m_txt) print_line(m_txt)
@@ -285,6 +316,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Run options:\n");
+ OS::get_singleton()->print(" -- Separator for user-provided arguments. Following arguments are not used by the engine, but can be read from `OS.get_cmdline_user_args()`.\n");
#ifdef TOOLS_ENABLED
OS::get_singleton()->print(" -e, --editor Start the editor instead of running the scene.\n");
OS::get_singleton()->print(" -p, --project-manager Start the project manager, even if a project is auto-detected.\n");
@@ -325,6 +357,7 @@ void Main::print_help(const char *p_binary) {
}
OS::get_singleton()->print("].\n");
+ OS::get_singleton()->print(" --rendering-method <renderer> Renderer name. Requires driver support.\n");
OS::get_singleton()->print(" --rendering-driver <driver> Rendering driver (depends on display driver).\n");
OS::get_singleton()->print(" --gpu-index <device_index> Use a specific GPU (run with --verbose to get available device list).\n");
OS::get_singleton()->print(" --text-driver <driver> Text driver (Fonts, BiDi, shaping)\n");
@@ -343,6 +376,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --resolution <W>x<H> Request window resolution.\n");
OS::get_singleton()->print(" --position <X>,<Y> Request window position.\n");
OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n");
+ OS::get_singleton()->print(" --xr-mode <mode> Select XR mode (default/off/on).\n");
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Debug options:\n");
@@ -357,6 +391,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
#if defined(DEBUG_ENABLED)
OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n");
+ OS::get_singleton()->print(" --debug-paths Show path lines when running the scene.\n");
OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n");
OS::get_singleton()->print(" --debug-stringnames Print all StringName allocations to stdout when the engine quits.\n");
#endif
@@ -376,12 +411,15 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist.\n");
OS::get_singleton()->print(" --export-debug <preset> <path> Same as --export, but using the debug template.\n");
OS::get_singleton()->print(" --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format.\n");
- OS::get_singleton()->print(" --convert-3to4 Converts project from Godot 3.x to Godot 4.x.\n");
- OS::get_singleton()->print(" --validate-conversion-3to4 Shows what elements will be renamed when converting project from Godot 3.x to Godot 4.x.\n");
+ OS::get_singleton()->print(" --convert-3to4 [<max_file_kb>] [<max_line_size>] Converts project from Godot 3.x to Godot 4.x.\n");
+ OS::get_singleton()->print(" --validate-conversion-3to4 [<max_file_kb>] [<max_line_size>] Shows what elements will be renamed when converting project from Godot 3.x to Godot 4.x.\n");
OS::get_singleton()->print(" --doctool [<path>] Dump the engine API reference to the given <path> (defaults to current dir) in XML format, merging if existing files are found.\n");
OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n");
OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n");
+ OS::get_singleton()->print(" --dump-gdextension-interface Generate GDExtension header file 'gdnative_interface.h' in the current folder. This file is the base file required to implement a GDExtension.\n");
OS::get_singleton()->print(" --dump-extension-api Generate JSON dump of the Godot API for GDExtension bindings named 'extension_api.json' in the current folder.\n");
+ OS::get_singleton()->print(" --startup-benchmark Benchmark the startup time and print it to console.\n");
+ OS::get_singleton()->print(" --startup-benchmark-file <path> Benchmark the startup time and save it to a given file in JSON format.\n");
#ifdef TESTS_ENABLED
OS::get_singleton()->print(" --test [--help] Run unit tests. Use --test --help for more information.\n");
#endif
@@ -408,6 +446,8 @@ Error Main::test_setup() {
String("Please include this when reporting the bug on https://github.com/godotengine/godot/issues"));
GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
+ register_core_settings(); //here globals are present
+
translation_server = memnew(TranslationServer);
tsman = memnew(TextServerManager);
@@ -417,6 +457,9 @@ Error Main::test_setup() {
tsman->add_interface(ts);
}
+ physics_server_3d_manager = memnew(PhysicsServer3DManager);
+ physics_server_2d_manager = memnew(PhysicsServer2DManager);
+
// From `Main::setup2()`.
initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
register_core_extensions();
@@ -425,6 +468,7 @@ Error Main::test_setup() {
/** INITIALIZE SERVERS **/
register_server_types();
+ XRServer::set_xr_mode(XRServer::XRMODE_OFF); // Skip in tests.
initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
@@ -455,7 +499,8 @@ Error Main::test_setup() {
register_platform_apis();
// Theme needs modules to be initialized so that sub-resources can be loaded.
- initialize_theme();
+ initialize_theme_db();
+ register_scene_singletons();
ERR_FAIL_COND_V(TextServerManager::get_singleton()->get_interface_count() == 0, ERR_CANT_CREATE);
@@ -506,6 +551,8 @@ void Main::test_cleanup() {
unregister_driver_types();
unregister_scene_types();
+ finalize_theme_db();
+
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
unregister_server_types();
@@ -518,6 +565,12 @@ void Main::test_cleanup() {
if (tsman) {
memdelete(tsman);
}
+ if (physics_server_3d_manager) {
+ memdelete(physics_server_3d_manager);
+ }
+ if (physics_server_2d_manager) {
+ memdelete(physics_server_2d_manager);
+ }
if (globals) {
memdelete(globals);
}
@@ -587,6 +640,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
engine = memnew(Engine);
MAIN_PRINT("Main: Initialize CORE");
+ engine->startup_begin();
+ engine->startup_benchmark_begin_measure("core");
register_core_types();
register_core_driver_types();
@@ -619,11 +674,20 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
/* argument parsing and main creation */
List<String> args;
List<String> main_args;
+ List<String> user_args;
+ bool adding_user_args = false;
+ List<String> platform_args = OS::get_singleton()->get_cmdline_platform_args();
+ // Add command line arguments.
for (int i = 0; i < argc; i++) {
args.push_back(String::utf8(argv[i]));
}
+ // Add arguments received from macOS LaunchService (URL schemas, file associations).
+ for (const String &arg : platform_args) {
+ args.push_back(arg);
+ }
+
List<String>::Element *I = args.front();
while (I) {
@@ -647,11 +711,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Vector<String> breakpoints;
bool use_custom_res = true;
bool force_res = false;
-#ifdef TOOLS_ENABLED
- bool found_project = false;
-#endif
String default_renderer = "";
+ String default_renderer_mobile = "";
String renderer_hints = "";
packed_data = PackedData::get_singleton();
@@ -671,9 +733,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
packed_data->add_pack_source(zip_packed_data);
#endif
+ // Default exit code, can be modified for certain errors.
+ Error exit_code = ERR_INVALID_PARAMETER;
+
I = args.front();
while (I) {
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
// Ignore the process serial number argument passed by macOS Gatekeeper.
// Otherwise, Godot would try to open a non-existent project on the first start and abort.
if (I->get().begins_with("-psn_")) {
@@ -681,15 +746,41 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
continue;
}
#endif
+
List<String>::Element *N = I->next();
- if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help
+#ifdef TOOLS_ENABLED
+ if (I->get() == "--debug" ||
+ I->get() == "--verbose" ||
+ I->get() == "--disable-crash-handler") {
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get());
+ forwardable_cli_arguments[CLI_SCOPE_PROJECT].push_back(I->get());
+ }
+ if (I->get() == "--single-window") {
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get());
+ }
+ if (I->get() == "--audio-driver" ||
+ I->get() == "--display-driver" ||
+ I->get() == "--rendering-method" ||
+ I->get() == "--rendering-driver") {
+ if (I->next()) {
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get());
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->next()->get());
+ }
+ }
+#endif
+
+ if (adding_user_args) {
+ user_args.push_back(I->get());
+ } else if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help
show_help = true;
+ exit_code = ERR_HELP; // Hack to force an early exit in `main()` with a success code.
goto error;
} else if (I->get() == "--version") {
print_line(get_full_version_string());
+ exit_code = ERR_HELP; // Hack to force an early exit in `main()` with a success code.
goto error;
} else if (I->get() == "-v" || I->get() == "--verbose") { // verbose output
@@ -780,43 +871,17 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->print("Missing display driver argument, aborting.\n");
goto error;
}
+ } else if (I->get() == "--rendering-method") {
+ if (I->next()) {
+ rendering_method = I->next()->get();
+ N = I->next()->next();
+ } else {
+ OS::get_singleton()->print("Missing renderer name argument, aborting.\n");
+ goto error;
+ }
} else if (I->get() == "--rendering-driver") {
if (I->next()) {
rendering_driver = I->next()->get();
-
- // as the rendering drivers available may depend on the display driver selected,
- // we can't do an exhaustive check here, but we can look through all the options in
- // all the display drivers for a match
-
- bool found = false;
- for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
- Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
-
- for (int d = 0; d < r_drivers.size(); d++) {
- if (rendering_driver == r_drivers[d]) {
- found = true;
- break;
- }
- }
- }
-
- if (!found) {
- OS::get_singleton()->print("Unknown rendering driver '%s', aborting.\nValid options are ",
- rendering_driver.utf8().get_data());
-
- for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
- Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
-
- for (int d = 0; d < r_drivers.size(); d++) {
- OS::get_singleton()->print("'%s', ", r_drivers[d].utf8().get_data());
- }
- }
-
- OS::get_singleton()->print(".\n");
-
- goto error;
- }
-
N = I->next()->next();
} else {
OS::get_singleton()->print("Missing rendering driver argument, aborting.\n");
@@ -857,7 +922,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
} else if (I->get() == "--single-window") { // force single window
- OS::get_singleton()->_single_window = true;
+ single_window = true;
} else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window
init_always_on_top = true;
@@ -992,6 +1057,16 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
auto_build_solutions = true;
editor = true;
cmdline_tool = true;
+ } else if (I->get() == "--dump-gdextension-interface") {
+ // Register as an editor instance to use low-end fallback if relevant.
+ editor = true;
+ cmdline_tool = true;
+ dump_gdnative_interface = true;
+ print_line("Dumping gdnative interface header file");
+ // Hack. Not needed but otherwise we end up detecting that this should
+ // run the project instead of a cmdline tool.
+ // Needs full refactoring to fix properly.
+ main_args.push_back(I->get());
} else if (I->get() == "--dump-extension-api") {
// Register as an editor instance to use low-end fallback if relevant.
editor = true;
@@ -1012,10 +1087,32 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// Actually handling is done in start().
cmdline_tool = true;
main_args.push_back(I->get());
+
+ if (I->next() && !I->next()->get().begins_with("-")) {
+ if (itos(I->next()->get().to_int()) == I->next()->get()) {
+ converter_max_kb_file = I->next()->get().to_int();
+ }
+ if (I->next()->next() && !I->next()->next()->get().begins_with("-")) {
+ if (itos(I->next()->next()->get().to_int()) == I->next()->next()->get()) {
+ converter_max_line_length = I->next()->next()->get().to_int();
+ }
+ }
+ }
} else if (I->get() == "--validate-conversion-3to4") {
// Actually handling is done in start().
cmdline_tool = true;
main_args.push_back(I->get());
+
+ if (I->next() && !I->next()->get().begins_with("-")) {
+ if (itos(I->next()->get().to_int()) == I->next()->get()) {
+ converter_max_kb_file = I->next()->get().to_int();
+ }
+ if (I->next()->next() && !I->next()->next()->get().begins_with("-")) {
+ if (itos(I->next()->next()->get().to_int()) == I->next()->next()->get()) {
+ converter_max_line_length = I->next()->next()->get().to_int();
+ }
+ }
+ }
} else if (I->get() == "--doctool") {
// Actually handling is done in start().
cmdline_tool = true;
@@ -1030,10 +1127,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (I->next()) {
String p = I->next()->get();
- if (OS::get_singleton()->set_cwd(p) == OK) {
- //nothing
- } else {
- project_path = I->next()->get(); //use project_path instead
+ if (OS::get_singleton()->set_cwd(p) != OK) {
+ OS::get_singleton()->print("Invalid project path specified: \"%s\", aborting.\n", p.utf8().get_data());
+ goto error;
}
N = I->next()->next();
} else {
@@ -1107,6 +1203,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#if defined(DEBUG_ENABLED)
} else if (I->get() == "--debug-collisions") {
debug_collisions = true;
+ } else if (I->get() == "--debug-paths") {
+ debug_paths = true;
} else if (I->get() == "--debug-navigation") {
debug_navigation = true;
} else if (I->get() == "--debug-stringnames") {
@@ -1125,9 +1223,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->print("Missing remote debug host address, aborting.\n");
goto error;
}
- } else if (I->get() == "--allow_focus_steal_pid") { // not exposed to user
+ } else if (I->get() == "--editor-pid") { // not exposed to user
if (I->next()) {
- allow_focus_steal_pid = I->next()->get().to_int();
+ editor_pid = I->next()->get().to_int();
N = I->next()->next();
} else {
OS::get_singleton()->print("Missing editor PID argument, aborting.\n");
@@ -1145,7 +1243,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
} else if (I->get() == "--write-movie") {
if (I->next()) {
- write_movie_path = I->next()->get();
+ Engine::get_singleton()->set_write_movie_path(I->next()->get());
N = I->next()->next();
if (fixed_fps == -1) {
fixed_fps = 60;
@@ -1165,6 +1263,39 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->disable_crash_handler();
} else if (I->get() == "--skip-breakpoints") {
skip_breakpoints = true;
+ } else if (I->get() == "--xr-mode") {
+ if (I->next()) {
+ String xr_mode = I->next()->get().to_lower();
+ N = I->next()->next();
+ if (xr_mode == "default") {
+ XRServer::set_xr_mode(XRServer::XRMODE_DEFAULT);
+ } else if (xr_mode == "off") {
+ XRServer::set_xr_mode(XRServer::XRMODE_OFF);
+ } else if (xr_mode == "on") {
+ XRServer::set_xr_mode(XRServer::XRMODE_ON);
+ } else {
+ OS::get_singleton()->print("Unknown --xr-mode argument \"%s\", aborting.\n", xr_mode.ascii().get_data());
+ goto error;
+ }
+ } else {
+ OS::get_singleton()->print("Missing --xr-mode argument, aborting.\n");
+ goto error;
+ }
+
+ } else if (I->get() == "--startup-benchmark") {
+ use_startup_benchmark = true;
+ } else if (I->get() == "--startup-benchmark-file") {
+ if (I->next()) {
+ use_startup_benchmark = true;
+ startup_benchmark_file = I->next()->get();
+ N = I->next()->next();
+ } else {
+ OS::get_singleton()->print("Missing <path> argument for --startup-benchmark-file <path>.\n");
+ goto error;
+ }
+
+ } else if (I->get() == "--") {
+ adding_user_args = true;
} else {
main_args.push_back(I->get());
}
@@ -1257,7 +1388,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
PROPERTY_HINT_RANGE,
"0, 200, 1, or_greater"));
- EngineDebugger::initialize(debug_uri, skip_breakpoints, breakpoints);
+ EngineDebugger::initialize(debug_uri, skip_breakpoints, breakpoints, []() {
+ if (editor_pid) {
+ DisplayServer::get_singleton()->enable_for_stealing_focus(editor_pid);
+ }
+ });
#ifdef TOOLS_ENABLED
if (editor) {
@@ -1324,60 +1459,213 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
input_map->load_from_project_settings(); //keys for game
}
- if (bool(ProjectSettings::get_singleton()->get("application/run/disable_stdout"))) {
+ if (bool(GLOBAL_GET("application/run/disable_stdout"))) {
quiet_stdout = true;
}
- if (bool(ProjectSettings::get_singleton()->get("application/run/disable_stderr"))) {
- _print_error_enabled = false;
+ if (bool(GLOBAL_GET("application/run/disable_stderr"))) {
+ CoreGlobals::print_error_enabled = false;
};
if (quiet_stdout) {
- _print_line_enabled = false;
+ CoreGlobals::print_line_enabled = false;
}
- Logger::set_flush_stdout_on_print(ProjectSettings::get_singleton()->get("application/run/flush_stdout_on_print"));
+ Logger::set_flush_stdout_on_print(GLOBAL_GET("application/run/flush_stdout_on_print"));
- OS::get_singleton()->set_cmdline(execpath, main_args);
+ OS::get_singleton()->set_cmdline(execpath, main_args, user_args);
- // possibly be worth changing the default from vulkan to something lower spec,
- // for the project manager, depending on how smooth the fallback is.
+ {
+ String driver_hints = "";
+#ifdef VULKAN_ENABLED
+ driver_hints = "vulkan";
+#endif
- // this list is hard coded, which makes it more difficult to add new backends.
- // can potentially be changed to more of a plugin system at a later date.
+ String default_driver = driver_hints.get_slice(",", 0);
+
+ // For now everything defaults to vulkan when available. This can change in future updates.
+ GLOBAL_DEF("rendering/rendering_device/driver", default_driver);
+ GLOBAL_DEF("rendering/rendering_device/driver.windows", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.windows",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.windows", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/rendering_device/driver.linuxbsd", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.linuxbsd",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/rendering_device/driver.android", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.android",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.android", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/rendering_device/driver.ios", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.ios",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.ios", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/rendering_device/driver.macos", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/rendering_device/driver.macos",
+ PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.macos", PROPERTY_HINT_ENUM, driver_hints));
+
+ driver_hints = "";
+#ifdef GLES3_ENABLED
+ driver_hints += "opengl3";
+#endif
- // Start with Vulkan, which will be the default if enabled.
+ default_driver = driver_hints.get_slice(",", 0);
+
+ GLOBAL_DEF("rendering/gl_compatibility/driver", default_driver);
+ GLOBAL_DEF("rendering/gl_compatibility/driver.windows", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.windows",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.linuxbsd", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.linuxbsd",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.web", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.web",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.android", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.android",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.ios", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.ios",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ENUM, driver_hints));
+ GLOBAL_DEF("rendering/gl_compatibility/driver.macos", default_driver);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/driver.macos",
+ PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, driver_hints));
+ }
+
+ // Start with RenderingDevice-based backends. Should be included if any RD driver present.
#ifdef VULKAN_ENABLED
- renderer_hints = "vulkan";
+ renderer_hints = "forward_plus,mobile";
+ default_renderer_mobile = "mobile";
#endif
- // And OpenGL3 next, or first if Vulkan is disabled.
+ // And Compatibility next, or first if Vulkan is disabled.
#ifdef GLES3_ENABLED
if (!renderer_hints.is_empty()) {
renderer_hints += ",";
}
- renderer_hints += "opengl3";
+ renderer_hints += "gl_compatibility";
+ if (default_renderer_mobile.is_empty()) {
+ default_renderer_mobile = "gl_compatibility";
+ }
#endif
if (renderer_hints.is_empty()) {
- ERR_PRINT("No rendering driver available.");
+ ERR_PRINT("No renderers available.");
+ }
+
+ if (!rendering_method.is_empty()) {
+ if (rendering_method != "forward_plus" &&
+ rendering_method != "mobile" &&
+ rendering_method != "gl_compatibility") {
+ OS::get_singleton()->print("Unknown renderer name '%s', aborting. Valid options are: %s\n", rendering_method.utf8().get_data(), renderer_hints.utf8().get_data());
+ goto error;
+ }
+ }
+
+ if (!rendering_driver.is_empty()) {
+ // As the rendering drivers available may depend on the display driver and renderer
+ // selected, we can't do an exhaustive check here, but we can look through all
+ // the options in all the display drivers for a match.
+
+ bool found = false;
+ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
+ Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
+
+ for (int d = 0; d < r_drivers.size(); d++) {
+ if (rendering_driver == r_drivers[d]) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ OS::get_singleton()->print("Unknown rendering driver '%s', aborting.\nValid options are ",
+ rendering_driver.utf8().get_data());
+
+ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
+ Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
+
+ for (int d = 0; d < r_drivers.size(); d++) {
+ OS::get_singleton()->print("'%s', ", r_drivers[d].utf8().get_data());
+ }
+ }
+
+ OS::get_singleton()->print(".\n");
+
+ goto error;
+ }
+
+ // Set a default renderer if none selected. Try to choose one that matches the driver.
+ if (rendering_method.is_empty()) {
+ if (rendering_driver == "opengl3") {
+ rendering_method = "gl_compatibility";
+ } else {
+ rendering_method = "forward_plus";
+ }
+ }
+
+ // Now validate whether the selected driver matches with the renderer.
+ bool valid_combination = false;
+ Vector<String> available_drivers;
+#ifdef VULKAN_ENABLED
+ if (rendering_method == "forward_plus" || rendering_method == "mobile") {
+ available_drivers.push_back("vulkan");
+ }
+#endif
+#ifdef GLES3_ENABLED
+ if (rendering_method == "gl_compatibility") {
+ available_drivers.push_back("opengl3");
+ }
+#endif
+ if (available_drivers.is_empty()) {
+ OS::get_singleton()->print("Unknown renderer name '%s', aborting.\n", rendering_method.utf8().get_data());
+ goto error;
+ }
+
+ for (int i = 0; i < available_drivers.size(); i++) {
+ if (rendering_driver == available_drivers[i]) {
+ valid_combination = true;
+ break;
+ }
+ }
+
+ if (!valid_combination) {
+ OS::get_singleton()->print("Invalid renderer/driver combination '%s' and '%s', aborting. %s only supports the following drivers ", rendering_method.utf8().get_data(), rendering_driver.utf8().get_data(), rendering_method.utf8().get_data());
+
+ for (int d = 0; d < available_drivers.size(); d++) {
+ OS::get_singleton()->print("'%s', ", available_drivers[d].utf8().get_data());
+ }
+
+ OS::get_singleton()->print(".\n");
+
+ goto error;
+ }
}
default_renderer = renderer_hints.get_slice(",", 0);
- GLOBAL_DEF_RST("rendering/driver/driver_name", default_renderer);
+ GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method", default_renderer);
+ GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method.mobile", default_renderer_mobile);
+ GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method.web", "gl_compatibility"); // This is a bit of a hack until we have WebGPU support.
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/driver/driver_name",
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/renderer/rendering_method",
PropertyInfo(Variant::STRING,
- "rendering/driver/driver_name",
+ "rendering/renderer/rendering_method",
PROPERTY_HINT_ENUM, renderer_hints));
- // if not set on the command line
+ // Default to ProjectSettings default if nothing set on the command line.
+ if (rendering_method.is_empty()) {
+ rendering_method = GLOBAL_GET("rendering/renderer/rendering_method");
+ }
+
if (rendering_driver.is_empty()) {
- rendering_driver = GLOBAL_GET("rendering/driver/driver_name");
+ if (rendering_method == "gl_compatibility") {
+ rendering_driver = GLOBAL_GET("rendering/gl_compatibility/driver");
+ } else {
+ rendering_driver = GLOBAL_GET("rendering/rendering_device/driver");
+ }
}
// note this is the desired rendering driver, it doesn't mean we will get it.
// TODO - make sure this is updated in the case of fallbacks, so that the user interface
// shows the correct driver string.
OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
+ OS::get_singleton()->set_current_rendering_method(rendering_method);
// always convert to lower case for consistency in the code
rendering_driver = rendering_driver.to_lower();
@@ -1406,56 +1694,50 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (bool(GLOBAL_GET("display/window/size/borderless"))) {
window_flags |= DisplayServer::WINDOW_FLAG_BORDERLESS_BIT;
}
- if (bool(GLOBAL_GET("display/window/size/fullscreen"))) {
- window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
- }
-
if (bool(GLOBAL_GET("display/window/size/always_on_top"))) {
window_flags |= DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP_BIT;
}
+ if (bool(GLOBAL_GET("display/window/size/transparent"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_TRANSPARENT_BIT;
+ }
+ if (bool(GLOBAL_GET("display/window/size/extend_to_title"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE_BIT;
+ }
+ if (bool(GLOBAL_GET("display/window/size/no_focus"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT;
+ }
+ window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int());
}
- GLOBAL_DEF("internationalization/rendering/force_right_to_left_layout_direction", false);
+ GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false);
GLOBAL_DEF("internationalization/locale/include_text_server_data", false);
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", true);
-
- // FIXME: Restore support.
-#if 0
- //OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
- video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency/enabled", false);
-#endif
+ OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
if (editor || project_manager) {
// The editor and project manager always detect and use hiDPI if needed
OS::get_singleton()->_allow_hidpi = true;
- OS::get_singleton()->_allow_layered = false;
}
- OS::get_singleton()->_keep_screen_on = GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
if (rtm == -1) {
rtm = GLOBAL_DEF("rendering/driver/threads/thread_model", OS::RENDER_THREAD_SAFE);
}
if (rtm >= 0 && rtm < 3) {
-#ifdef NO_THREADS
- rtm = OS::RENDER_THREAD_UNSAFE; // No threads available on this platform.
-#else
if (editor) {
rtm = OS::RENDER_THREAD_SAFE;
}
-#endif
OS::get_singleton()->_render_thread_mode = OS::RenderThreadMode(rtm);
}
/* Determine audio and video drivers */
// Display driver, e.g. X11, Wayland.
- // print_line("requested display driver : " + display_driver);
+ // Make sure that headless is the last one, which it is assumed to be by design.
+ DEV_ASSERT(String("headless") == DisplayServer::get_create_function_name(DisplayServer::get_create_function_count() - 1));
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
String name = DisplayServer::get_create_function_name(i);
- // print_line("\t" + itos(i) + " : " + name);
-
if (display_driver == name) {
display_driver_idx = i;
break;
@@ -1463,6 +1745,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
if (display_driver_idx < 0) {
+ // If the requested driver wasn't found, pick the first entry.
+ // If all else failed it would be the headless server.
display_driver_idx = 0;
}
@@ -1475,6 +1759,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
audio_driver = GLOBAL_GET("audio/driver/driver");
}
+ // Make sure that dummy is the last one, which it is assumed to be by design.
+ DEV_ASSERT(String("Dummy") == AudioDriverManager::get_driver(AudioDriverManager::get_driver_count() - 1)->get_name());
for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
if (audio_driver == AudioDriverManager::get_driver(i)->get_name()) {
audio_driver_idx = i;
@@ -1483,10 +1769,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
if (audio_driver_idx < 0) {
- audio_driver_idx = 0; // 0 Is always available as the dummy driver (no sound)
+ // If the requested driver wasn't found, pick the first entry.
+ // If all else failed it would be the dummy driver (no sound).
+ audio_driver_idx = 0;
}
- if (write_movie_path != String()) {
+ if (Engine::get_singleton()->get_write_movie_path() != String()) {
// Always use dummy driver for audio driver (which is last), also in no threaded mode.
audio_driver_idx = AudioDriverManager::get_driver_count() - 1;
AudioDriverDummy::get_dummy_singleton()->set_use_threads(false);
@@ -1506,10 +1794,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
PropertyInfo(Variant::INT, "physics/common/physics_ticks_per_second",
PROPERTY_HINT_RANGE, "1,1000,1"));
Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
- Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/settings/fps/force_fps", 0));
- ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/fps/force_fps",
+ Engine::get_singleton()->set_max_fps(GLOBAL_DEF("application/run/max_fps", 0));
+ ProjectSettings::get_singleton()->set_custom_property_info("application/run/max_fps",
PropertyInfo(Variant::INT,
- "debug/settings/fps/force_fps",
+ "application/run/max_fps",
PROPERTY_HINT_RANGE, "0,1000,1"));
GLOBAL_DEF("debug/settings/stdout/print_fps", false);
@@ -1539,6 +1827,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
"0,33200,1,or_greater")); // No negative numbers
GLOBAL_DEF("display/window/ios/hide_home_indicator", true);
+ GLOBAL_DEF("display/window/ios/hide_status_bar", true);
+ GLOBAL_DEF("display/window/ios/suppress_ui_gesture", true);
GLOBAL_DEF("input_devices/pointing/ios/touch_delay", 0.15);
ProjectSettings::get_singleton()->set_custom_property_info("input_devices/pointing/ios/touch_delay",
PropertyInfo(Variant::FLOAT,
@@ -1571,6 +1861,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
message_queue = memnew(MessageQueue);
+ engine->startup_benchmark_end_measure(); // core
+
if (p_second_phase) {
return setup2();
}
@@ -1583,7 +1875,7 @@ error:
display_driver = "";
audio_driver = "";
tablet_driver = "";
- write_movie_path = "";
+ Engine::get_singleton()->set_write_movie_path(String());
project_path = "";
args.clear();
@@ -1625,6 +1917,7 @@ error:
unregister_core_types();
OS::get_singleton()->_cmdline.clear();
+ OS::get_singleton()->_user_args.clear();
if (message_queue) {
memdelete(message_queue);
@@ -1632,10 +1925,12 @@ error:
OS::get_singleton()->finalize_core();
locale = String();
- return ERR_INVALID_PARAMETER;
+ return exit_code;
}
Error Main::setup2(Thread::ID p_main_tid_override) {
+ engine->startup_benchmark_begin_measure("servers");
+
tsman = memnew(TextServerManager);
if (tsman) {
@@ -1644,6 +1939,9 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
tsman->add_interface(ts);
}
+ physics_server_3d_manager = memnew(PhysicsServer3DManager);
+ physics_server_2d_manager = memnew(PhysicsServer2DManager);
+
register_server_types();
initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
@@ -1651,15 +1949,20 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
// Print engine name and version
print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE));
-#if !defined(NO_THREADS)
if (p_main_tid_override) {
Thread::main_thread_id = p_main_tid_override;
}
-#endif
#ifdef TOOLS_ENABLED
if (editor || project_manager || cmdline_tool) {
EditorPaths::create();
+ if (found_project && EditorPaths::get_singleton()->is_self_contained()) {
+ if (ProjectSettings::get_singleton()->get_resource_path() == OS::get_singleton()->get_executable_path().get_base_dir()) {
+ ERR_PRINT("You are trying to run a self-contained editor at the same location as a project. This is not allowed, since editor files will mix with project files.");
+ OS::get_singleton()->set_exit_code(EXIT_FAILURE);
+ return FAILED;
+ }
+ }
}
#endif
@@ -1672,16 +1975,24 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
{
String display_driver = DisplayServer::get_create_function_name(display_driver_idx);
+ Vector2i *window_position = nullptr;
+ Vector2i position = init_custom_pos;
+ if (init_use_custom_pos) {
+ window_position = &position;
+ }
+
// rendering_driver now held in static global String in main and initialized in setup()
Error err;
- display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err);
+ display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, err);
if (err != OK || display_server == nullptr) {
- //ok i guess we can't use this display server, try other ones
- for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
+ // We can't use this display server, try other ones as fallback.
+ // Skip headless (always last registered) because that's not what users
+ // would expect if they didn't request it explicitly.
+ for (int i = 0; i < DisplayServer::get_create_function_count() - 1; i++) {
if (i == display_driver_idx) {
- continue; //don't try the same twice
+ continue; // Don't try the same twice.
}
- display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err);
+ display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, err);
if (err == OK && display_server != nullptr) {
break;
}
@@ -1756,11 +2067,11 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
rendering_server->set_print_gpu_profile(true);
}
- if (write_movie_path != String()) {
- movie_writer = MovieWriter::find_writer_for_file(write_movie_path);
+ if (Engine::get_singleton()->get_write_movie_path() != String()) {
+ movie_writer = MovieWriter::find_writer_for_file(Engine::get_singleton()->get_write_movie_path());
if (movie_writer == nullptr) {
- ERR_PRINT("Can't find movie writer for file type, aborting: " + write_movie_path);
- write_movie_path = String();
+ ERR_PRINT("Can't find movie writer for file type, aborting: " + Engine::get_singleton()->get_write_movie_path());
+ Engine::get_singleton()->set_write_movie_path(String());
}
}
@@ -1795,7 +2106,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: Setup Logo");
-#if defined(JAVASCRIPT_ENABLED) || defined(ANDROID_ENABLED)
+#if defined(WEB_ENABLED) || defined(ANDROID_ENABLED)
bool show_logo = false;
#else
bool show_logo = true;
@@ -1815,10 +2126,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP, true);
}
- if (allow_focus_steal_pid) {
- DisplayServer::get_singleton()->enable_for_stealing_focus(allow_focus_steal_pid);
- }
-
MAIN_PRINT("Main: Load Boot Image");
Color clear = GLOBAL_DEF_BASIC("rendering/environment/defaults/default_clear_color", Color(0.3, 0.3, 0.3));
@@ -1847,7 +2154,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
} else {
// Create a 1×1 transparent image. This will effectively hide the splash image.
boot_logo.instantiate();
- boot_logo->create(1, 1, false, Image::FORMAT_RGBA8);
+ boot_logo->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
boot_logo->set_pixel(0, 0, Color(0, 0, 0, 0));
}
@@ -1942,13 +2249,19 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: Load TextServer");
/* Enum text drivers */
- GLOBAL_DEF("internationalization/rendering/text_driver", "");
+ GLOBAL_DEF_RST("internationalization/rendering/text_driver", "");
String text_driver_options;
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
- if (i > 0) {
+ const String driver_name = TextServerManager::get_singleton()->get_interface(i)->get_name();
+ if (driver_name == "Dummy") {
+ // Dummy text driver cannot draw any text, making the editor unusable if selected.
+ continue;
+ }
+ if (!text_driver_options.is_empty() && text_driver_options.find(",") == -1) {
+ // Not the first option; add a comma before it as a separator for the property hint.
text_driver_options += ",";
}
- text_driver_options += TextServerManager::get_singleton()->get_interface(i)->get_name();
+ text_driver_options += driver_name;
}
ProjectSettings::get_singleton()->set_custom_property_info("internationalization/rendering/text_driver", PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options));
@@ -1989,8 +2302,12 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "TextServer: Unable to create TextServer interface.");
}
+ engine->startup_benchmark_end_measure(); // servers
+
MAIN_PRINT("Main: Load Scene Types");
+ engine->startup_benchmark_begin_measure("scene");
+
register_scene_types();
register_driver_types();
@@ -2012,7 +2329,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
register_platform_apis();
// Theme needs modules to be initialized so that sub-resources can be loaded.
- initialize_theme();
+ initialize_theme_db();
+ register_scene_singletons();
GLOBAL_DEF_BASIC("display/mouse_cursor/custom_image", String());
GLOBAL_DEF_BASIC("display/mouse_cursor/custom_image_hotspot", Vector2());
@@ -2022,11 +2340,11 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
"display/mouse_cursor/custom_image",
PROPERTY_HINT_FILE, "*.png,*.webp"));
- if (String(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image")) != String()) {
+ if (String(GLOBAL_GET("display/mouse_cursor/custom_image")) != String()) {
Ref<Texture2D> cursor = ResourceLoader::load(
- ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image"));
+ GLOBAL_GET("display/mouse_cursor/custom_image"));
if (cursor.is_valid()) {
- Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot");
+ Vector2 hotspot = GLOBAL_GET("display/mouse_cursor/custom_image_hotspot");
Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot);
}
}
@@ -2055,7 +2373,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
// able to load resources, load the global shader variables.
// If running on editor, don't load the textures because the editor
// may want to import them first. Editor will reload those later.
- rendering_server->global_variables_load_settings(!editor);
+ rendering_server->global_shader_parameters_load_settings(!editor);
}
_start_success = true;
@@ -2066,6 +2384,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
print_verbose("EDITOR API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_EDITOR)));
MAIN_PRINT("Main: Done");
+ engine->startup_benchmark_end_measure(); // scene
+
return OK;
}
@@ -2175,6 +2495,13 @@ bool Main::start() {
#endif
}
+ uint64_t minimum_time_msec = GLOBAL_DEF("application/boot_splash/minimum_display_time", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("application/boot_splash/minimum_display_time",
+ PropertyInfo(Variant::INT,
+ "application/boot_splash/minimum_display_time",
+ PROPERTY_HINT_RANGE,
+ "0,100,1,or_greater,suffix:ms")); // No negative numbers.
+
#ifdef TOOLS_ENABLED
if (!doc_tool_path.is_empty()) {
// Needed to instance editor-only classes for their default values
@@ -2190,18 +2517,6 @@ bool Main::start() {
ERR_FAIL_COND_V_MSG(da.is_null(), false, "Argument supplied to --doctool must be a valid directory path.");
}
-#ifndef MODULE_MONO_ENABLED
- // Hack to define Mono-specific project settings even on non-Mono builds,
- // so that we don't lose their descriptions and default values in DocData.
- // Default values should be synced with mono_gd/gd_mono.cpp.
- GLOBAL_DEF("mono/debugger_agent/port", 23685);
- GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false);
- GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000);
- GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd");
- GLOBAL_DEF("mono/profiler/enabled", false);
- GLOBAL_DEF("mono/runtime/unhandled_exception_policy", 0);
-#endif
-
Error err;
DocTools doc;
doc.generate(doc_base);
@@ -2215,7 +2530,7 @@ bool Main::start() {
// Custom modules are always located by absolute path.
String path = _doc_data_class_paths[i].path;
if (path.is_relative_path()) {
- path = doc_tool_path.plus_file(path);
+ path = doc_tool_path.path_join(path);
}
String name = _doc_data_class_paths[i].name;
doc_data_classes[name] = path;
@@ -2233,7 +2548,7 @@ bool Main::start() {
}
}
- String index_path = doc_tool_path.plus_file("doc/classes");
+ String index_path = doc_tool_path.path_join("doc/classes");
// Create the main documentation directory if it doesn't exist
Ref<DirAccess> da = DirAccess::create_for_path(index_path);
err = da->make_dir_recursive(index_path);
@@ -2261,18 +2576,25 @@ bool Main::start() {
return false;
}
+ if (dump_gdnative_interface) {
+ GDNativeInterfaceDump::generate_gdnative_interface_file("gdnative_interface.h");
+ }
+
if (dump_extension_api) {
NativeExtensionAPIDump::generate_extension_json_file("extension_api.json");
+ }
+
+ if (dump_gdnative_interface || dump_extension_api) {
return false;
}
if (converting_project) {
- int exit_code = ProjectConverter3To4().convert();
+ int exit_code = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).convert();
OS::get_singleton()->set_exit_code(exit_code);
return false;
}
if (validating_converting_project) {
- int exit_code = ProjectConverter3To4().validate_conversion();
+ int exit_code = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).validate_conversion();
OS::get_singleton()->set_exit_code(exit_code);
return false;
}
@@ -2375,14 +2697,19 @@ bool Main::start() {
if (debug_collisions) {
sml->set_debug_collisions_hint(true);
}
+ if (debug_paths) {
+ sml->set_debug_paths_hint(true);
+ }
if (debug_navigation) {
sml->set_debug_navigation_hint(true);
+ NavigationServer3D::get_singleton()->set_active(true);
+ NavigationServer3D::get_singleton_mut()->set_debug_enabled(true);
}
#endif
bool embed_subwindows = GLOBAL_DEF("display/window/subwindows/embed_subwindows", true);
- if (OS::get_singleton()->is_single_window() || (!project_manager && !editor && embed_subwindows) || !DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) {
+ if (single_window || (!project_manager && !editor && embed_subwindows) || !DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) {
sml->get_root()->set_embedding_subwindows(true);
}
@@ -2392,6 +2719,7 @@ bool Main::start() {
if (!project_manager && !editor) { // game
if (!game_path.is_empty() || !script.is_empty()) {
//autoload
+ Engine::get_singleton()->startup_benchmark_begin_measure("load_autoloads");
HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
//first pass, add the constants so they exist before any script is loaded
@@ -2446,12 +2774,14 @@ bool Main::start() {
for (Node *E : to_add) {
sml->get_root()->add_child(E);
}
+ Engine::get_singleton()->startup_benchmark_end_measure(); // load autoloads
}
}
#ifdef TOOLS_ENABLED
EditorNode *editor_node = nullptr;
if (editor) {
+ Engine::get_singleton()->startup_benchmark_begin_measure("editor");
editor_node = memnew(EditorNode);
sml->get_root()->add_child(editor_node);
@@ -2459,6 +2789,13 @@ bool Main::start() {
editor_node->export_preset(_export_preset, positional_arg, export_debug, export_pack_only);
game_path = ""; // Do not load anything.
}
+
+ Engine::get_singleton()->startup_benchmark_end_measure();
+
+ editor_node->set_use_startup_benchmark(use_startup_benchmark, startup_benchmark_file);
+ // Editor takes over
+ use_startup_benchmark = false;
+ startup_benchmark_file = String();
}
#endif
@@ -2496,7 +2833,7 @@ bool Main::start() {
sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
- String appname = ProjectSettings::get_singleton()->get("application/config/name");
+ String appname = GLOBAL_GET("application/config/name");
appname = TranslationServer::get_singleton()->translate(appname);
#ifdef DEBUG_ENABLED
// Append a suffix to the window title to denote that the project is running
@@ -2542,7 +2879,7 @@ bool Main::start() {
PropertyInfo(Variant::FLOAT,
"display/window/stretch/scale",
PROPERTY_HINT_RANGE,
- "1.0,8.0,0.1"));
+ "0.5,8.0,0.01"));
sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true);
@@ -2588,11 +2925,11 @@ bool Main::start() {
if (sep == -1) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- local_game_path = da->get_current_dir().plus_file(local_game_path);
+ local_game_path = da->get_current_dir().path_join(local_game_path);
} else {
Ref<DirAccess> da = DirAccess::open(local_game_path.substr(0, sep));
if (da.is_valid()) {
- local_game_path = da->get_current_dir().plus_file(
+ local_game_path = da->get_current_dir().path_join(
local_game_path.substr(sep + 1, local_game_path.length()));
}
}
@@ -2623,8 +2960,10 @@ bool Main::start() {
if (!project_manager && !editor) { // game
+ Engine::get_singleton()->startup_benchmark_begin_measure("game_load");
+
// Load SSL Certificates from Project Settings (or builtin).
- Crypto::load_default_certificates(GLOBAL_DEF("network/ssl/certificate_bundle_override", ""));
+ Crypto::load_default_certificates(GLOBAL_DEF("network/tls/certificate_bundle_override", ""));
if (!game_path.is_empty()) {
Node *scene = nullptr;
@@ -2636,7 +2975,7 @@ bool Main::start() {
ERR_FAIL_COND_V_MSG(!scene, false, "Failed loading scene: " + local_game_path);
sml->add_current_scene(scene);
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
String mac_iconpath = GLOBAL_DEF("application/config/macos_native_icon", "Variant()");
if (!mac_iconpath.is_empty()) {
DisplayServer::get_singleton()->set_native_icon(mac_iconpath);
@@ -2662,22 +3001,26 @@ bool Main::start() {
}
}
}
+
+ Engine::get_singleton()->startup_benchmark_end_measure(); // game_load
}
#ifdef TOOLS_ENABLED
if (project_manager) {
+ Engine::get_singleton()->startup_benchmark_begin_measure("project_manager");
Engine::get_singleton()->set_editor_hint(true);
ProjectManager *pmanager = memnew(ProjectManager);
ProgressDialog *progress_dialog = memnew(ProgressDialog);
pmanager->add_child(progress_dialog);
sml->get_root()->add_child(pmanager);
DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_PROJECTMAN);
+ Engine::get_singleton()->startup_benchmark_end_measure();
}
if (project_manager || editor) {
// Load SSL Certificates from Editor Settings (or builtin)
Crypto::load_default_certificates(
- EditorSettings::get_singleton()->get_setting("network/ssl/editor_ssl_certificates").operator String());
+ EditorSettings::get_singleton()->get_setting("network/tls/editor_tls_certificates").operator String());
}
#endif
}
@@ -2690,8 +3033,22 @@ bool Main::start() {
OS::get_singleton()->set_main_loop(main_loop);
if (movie_writer) {
- movie_writer->begin(DisplayServer::get_singleton()->window_get_size(), fixed_fps, write_movie_path);
+ movie_writer->begin(DisplayServer::get_singleton()->window_get_size(), fixed_fps, Engine::get_singleton()->get_write_movie_path());
}
+
+ if (minimum_time_msec) {
+ uint64_t minimum_time = 1000 * minimum_time_msec;
+ uint64_t elapsed_time = OS::get_singleton()->get_ticks_usec();
+ if (elapsed_time < minimum_time) {
+ OS::get_singleton()->delay_usec(minimum_time - elapsed_time);
+ }
+ }
+
+ if (use_startup_benchmark) {
+ Engine::get_singleton()->startup_dump(startup_benchmark_file);
+ startup_benchmark_file = String();
+ }
+
return true;
}
@@ -2937,6 +3294,7 @@ void Main::cleanup(bool p_force) {
OS::get_singleton()->delete_main_loop();
OS::get_singleton()->_cmdline.clear();
+ OS::get_singleton()->_user_args.clear();
OS::get_singleton()->_execpath = "";
OS::get_singleton()->_local_clipboard = "";
@@ -2949,7 +3307,7 @@ void Main::cleanup(bool p_force) {
RenderingServer::get_singleton()->sync();
//clear global shader variables before scene and other graphics stuff are deinitialized.
- rendering_server->global_variables_clear();
+ rendering_server->global_shader_parameters_clear();
if (xr_server) {
// Now that we're unregistering properly in plugins we need to keep access to xr_server for a little longer
@@ -2973,6 +3331,11 @@ void Main::cleanup(bool p_force) {
unregister_driver_types();
unregister_scene_types();
+ finalize_theme_db();
+
+ // Before deinitializing server extensions, finalize servers which may be loaded as extensions.
+ finalize_physics();
+
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
unregister_server_types();
@@ -2994,7 +3357,6 @@ void Main::cleanup(bool p_force) {
OS::get_singleton()->finalize();
- finalize_physics();
finalize_navigation_server();
finalize_display();
@@ -3023,6 +3385,12 @@ void Main::cleanup(bool p_force) {
if (tsman) {
memdelete(tsman);
}
+ if (physics_server_3d_manager) {
+ memdelete(physics_server_3d_manager);
+ }
+ if (physics_server_2d_manager) {
+ memdelete(physics_server_2d_manager);
+ }
if (globals) {
memdelete(globals);
}
diff --git a/main/main.h b/main/main.h
index d1870ab8df..f0bfe69b34 100644
--- a/main/main.h
+++ b/main/main.h
@@ -35,6 +35,9 @@
#include "core/os/thread.h"
#include "core/typedefs.h"
+template <class T>
+class Vector;
+
class Main {
static void print_help(const char *p_binary);
static uint64_t last_ticks;
@@ -47,6 +50,14 @@ class Main {
public:
static bool is_cmdline_tool();
+#ifdef TOOLS_ENABLED
+ enum CLIScope {
+ CLI_SCOPE_TOOL, // Editor and project manager.
+ CLI_SCOPE_PROJECT,
+ };
+ static const Vector<String> &get_forwardable_cli_arguments(CLIScope p_scope);
+#endif
+
static int test_entrypoint(int argc, char *argv[], bool &tests_need_run);
static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true);
static Error setup2(Thread::ID p_main_tid_override = 0);
diff --git a/main/performance.cpp b/main/performance.cpp
index 25659b999f..bdcd07a216 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -32,6 +32,7 @@
#include "core/object/message_queue.h"
#include "core/os/os.h"
+#include "core/variant/typed_array.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "servers/audio_server.h"
@@ -240,11 +241,11 @@ Variant Performance::get_custom_monitor(const StringName &p_id) {
return return_value;
}
-Array Performance::get_custom_monitor_names() {
+TypedArray<StringName> Performance::get_custom_monitor_names() {
if (!_monitor_map.size()) {
- return Array();
+ return TypedArray<StringName>();
}
- Array return_array;
+ TypedArray<StringName> return_array;
return_array.resize(_monitor_map.size());
int index = 0;
for (KeyValue<StringName, MonitorCall> i : _monitor_map) {
@@ -283,7 +284,7 @@ Variant Performance::MonitorCall::call(bool &r_error, String &r_error_message) {
int argc = _arguments.size();
Variant return_value;
Callable::CallError error;
- _callable.call(args, argc, return_value, error);
+ _callable.callp(args, argc, return_value, error);
r_error = (error.error != Callable::CallError::CALL_OK);
if (r_error) {
r_error_message = Variant::get_callable_error_text(_callable, args, argc, error);
diff --git a/main/performance.h b/main/performance.h
index 2837d8f512..597666b57d 100644
--- a/main/performance.h
+++ b/main/performance.h
@@ -37,6 +37,9 @@
#define PERF_WARN_OFFLINE_FUNCTION
#define PERF_WARN_PROCESS_SYNC
+template <typename T>
+class TypedArray;
+
class Performance : public Object {
GDCLASS(Performance, Object);
@@ -85,7 +88,6 @@ public:
PHYSICS_3D_ACTIVE_OBJECTS,
PHYSICS_3D_COLLISION_PAIRS,
PHYSICS_3D_ISLAND_COUNT,
- //physics
AUDIO_OUTPUT_LATENCY,
MONITOR_MAX
};
@@ -108,7 +110,7 @@ public:
void remove_custom_monitor(const StringName &p_id);
bool has_custom_monitor(const StringName &p_id);
Variant get_custom_monitor(const StringName &p_id);
- Array get_custom_monitor_names();
+ TypedArray<StringName> get_custom_monitor_names();
uint64_t get_monitor_modification_time();