2
0
Эх сурвалжийг харах

Improve logging and benchmarking in Main

Yuri Sizov 1 жил өмнө
parent
commit
d7cca8162d
1 өөрчлөгдсөн 288 нэмэгдсэн , 192 устгасан
  1. 288 192
      main/main.cpp

+ 288 - 192
main/main.cpp

@@ -766,6 +766,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 	// Benchmark tracking must be done after `OS::get_singleton()->initialize()` as on some
 	// platforms, it's used to set up the time utilities.
 	OS::get_singleton()->benchmark_begin_measure("Startup", "Total");
+	OS::get_singleton()->benchmark_begin_measure("Startup", "Setup");
 
 	engine = memnew(Engine);
 
@@ -2185,6 +2186,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 		return setup2();
 	}
 
+	OS::get_singleton()->benchmark_end_measure("Startup", "Setup");
 	return OK;
 
 error:
@@ -2239,6 +2241,7 @@ error:
 	}
 
 	OS::get_singleton()->benchmark_end_measure("Startup", "Core");
+	OS::get_singleton()->benchmark_end_measure("Startup", "Setup");
 
 	OS::get_singleton()->finalize_core();
 	locale = String();
@@ -2272,25 +2275,10 @@ Error Main::setup2() {
 	// Print engine name and version
 	print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE));
 
-	OS::get_singleton()->benchmark_begin_measure("Startup", "Servers");
-
-	tsman = memnew(TextServerManager);
-
-	if (tsman) {
-		Ref<TextServerDummy> ts;
-		ts.instantiate();
-		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);
-	GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
-
 #ifdef TOOLS_ENABLED
 	if (editor || project_manager || cmdline_tool) {
+		OS::get_singleton()->benchmark_begin_measure("Startup", "Initialize Early Settings");
+
 		EditorPaths::create();
 
 		// Editor setting class is not available, load config directly.
@@ -2352,16 +2340,49 @@ Error Main::setup2() {
 				return FAILED;
 			}
 		}
+
+		OS::get_singleton()->benchmark_end_measure("Startup", "Initialize Early Settings");
 	}
 #endif
 
+	OS::get_singleton()->benchmark_begin_measure("Startup", "Servers");
+
+	tsman = memnew(TextServerManager);
+	if (tsman) {
+		Ref<TextServerDummy> ts;
+		ts.instantiate();
+		tsman->add_interface(ts);
+	}
+
+	physics_server_3d_manager = memnew(PhysicsServer3DManager);
+	physics_server_2d_manager = memnew(PhysicsServer2DManager);
+
+	register_server_types();
+	{
+		OS::get_singleton()->benchmark_begin_measure("Servers", "Modules and Extensions");
+
+		initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
+		GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
+
+		OS::get_singleton()->benchmark_end_measure("Servers", "Modules and Extensions");
+	}
+
 	/* Initialize Input */
 
-	input = memnew(Input);
+	{
+		OS::get_singleton()->benchmark_begin_measure("Servers", "Input");
+
+		input = memnew(Input);
+		OS::get_singleton()->initialize_joypads();
+
+		OS::get_singleton()->benchmark_end_measure("Servers", "Input");
+	}
 
 	/* Initialize Display Server */
 
 	{
+		OS::get_singleton()->benchmark_begin_measure("Servers", "Display");
+
 		String display_driver = DisplayServer::get_create_function_name(display_driver_idx);
 
 		Vector2i *window_position = nullptr;
@@ -2395,10 +2416,12 @@ Error Main::setup2() {
 			ERR_PRINT("Unable to create DisplayServer, all display drivers failed.");
 			return err;
 		}
-	}
 
-	if (display_server->has_feature(DisplayServer::FEATURE_ORIENTATION)) {
-		display_server->screen_set_orientation(window_orientation);
+		if (display_server->has_feature(DisplayServer::FEATURE_ORIENTATION)) {
+			display_server->screen_set_orientation(window_orientation);
+		}
+
+		OS::get_singleton()->benchmark_end_measure("Servers", "Display");
 	}
 
 	if (GLOBAL_GET("debug/settings/stdout/print_fps") || print_fps) {
@@ -2426,48 +2449,58 @@ Error Main::setup2() {
 	/* Initialize Pen Tablet Driver */
 
 	{
+		OS::get_singleton()->benchmark_begin_measure("Servers", "Tablet Driver");
+
 		GLOBAL_DEF_RST_NOVAL("input_devices/pen_tablet/driver", "");
 		GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "input_devices/pen_tablet/driver.windows", PROPERTY_HINT_ENUM, "wintab,winink"), "");
-	}
 
-	if (tablet_driver.is_empty()) { // specified in project.godot
-		tablet_driver = GLOBAL_GET("input_devices/pen_tablet/driver");
-		if (tablet_driver.is_empty()) {
-			tablet_driver = DisplayServer::get_singleton()->tablet_get_driver_name(0);
+		if (tablet_driver.is_empty()) { // specified in project.godot
+			tablet_driver = GLOBAL_GET("input_devices/pen_tablet/driver");
+			if (tablet_driver.is_empty()) {
+				tablet_driver = DisplayServer::get_singleton()->tablet_get_driver_name(0);
+			}
 		}
-	}
 
-	for (int i = 0; i < DisplayServer::get_singleton()->tablet_get_driver_count(); i++) {
-		if (tablet_driver == DisplayServer::get_singleton()->tablet_get_driver_name(i)) {
-			DisplayServer::get_singleton()->tablet_set_current_driver(DisplayServer::get_singleton()->tablet_get_driver_name(i));
-			break;
+		for (int i = 0; i < DisplayServer::get_singleton()->tablet_get_driver_count(); i++) {
+			if (tablet_driver == DisplayServer::get_singleton()->tablet_get_driver_name(i)) {
+				DisplayServer::get_singleton()->tablet_set_current_driver(DisplayServer::get_singleton()->tablet_get_driver_name(i));
+				break;
+			}
 		}
-	}
 
-	if (DisplayServer::get_singleton()->tablet_get_current_driver().is_empty()) {
-		DisplayServer::get_singleton()->tablet_set_current_driver(DisplayServer::get_singleton()->tablet_get_driver_name(0));
-	}
+		if (DisplayServer::get_singleton()->tablet_get_current_driver().is_empty()) {
+			DisplayServer::get_singleton()->tablet_set_current_driver(DisplayServer::get_singleton()->tablet_get_driver_name(0));
+		}
+
+		print_verbose("Using \"" + tablet_driver + "\" pen tablet driver...");
 
-	print_verbose("Using \"" + tablet_driver + "\" pen tablet driver...");
+		OS::get_singleton()->benchmark_end_measure("Servers", "Tablet Driver");
+	}
 
 	/* Initialize Rendering Server */
 
-	rendering_server = memnew(RenderingServerDefault(OS::get_singleton()->get_render_thread_mode() == OS::RENDER_SEPARATE_THREAD));
+	{
+		OS::get_singleton()->benchmark_begin_measure("Servers", "Rendering");
 
-	rendering_server->init();
-	//rendering_server->call_set_use_vsync(OS::get_singleton()->_use_vsync);
-	rendering_server->set_render_loop_enabled(!disable_render_loop);
+		rendering_server = memnew(RenderingServerDefault(OS::get_singleton()->get_render_thread_mode() == OS::RENDER_SEPARATE_THREAD));
 
-	if (profile_gpu || (!editor && bool(GLOBAL_GET("debug/settings/stdout/print_gpu_profile")))) {
-		rendering_server->set_print_gpu_profile(true);
-	}
+		rendering_server->init();
+		//rendering_server->call_set_use_vsync(OS::get_singleton()->_use_vsync);
+		rendering_server->set_render_loop_enabled(!disable_render_loop);
 
-	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: " + Engine::get_singleton()->get_write_movie_path());
-			Engine::get_singleton()->set_write_movie_path(String());
+		if (profile_gpu || (!editor && bool(GLOBAL_GET("debug/settings/stdout/print_gpu_profile")))) {
+			rendering_server->set_print_gpu_profile(true);
 		}
+
+		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: " + Engine::get_singleton()->get_write_movie_path());
+				Engine::get_singleton()->set_write_movie_path(String());
+			}
+		}
+
+		OS::get_singleton()->benchmark_end_measure("Servers", "Rendering");
 	}
 
 #ifdef UNIX_ENABLED
@@ -2477,206 +2510,242 @@ Error Main::setup2() {
 	}
 #endif
 
-	OS::get_singleton()->initialize_joypads();
-
 	/* Initialize Audio Driver */
 
-	AudioDriverManager::initialize(audio_driver_idx);
+	{
+		OS::get_singleton()->benchmark_begin_measure("Servers", "Audio");
+
+		AudioDriverManager::initialize(audio_driver_idx);
 
-	print_line(" "); //add a blank line for readability
+		print_line(" "); // Add a blank line for readability.
 
-	// right moment to create and initialize the audio server
+		// Right moment to create and initialize the audio server.
+		audio_server = memnew(AudioServer);
+		audio_server->init();
 
-	audio_server = memnew(AudioServer);
-	audio_server->init();
+		OS::get_singleton()->benchmark_end_measure("Servers", "Audio");
+	}
+
+	/* Initialize XR Server */
 
-	// also init our xr_server from here
-	xr_server = memnew(XRServer);
+	{
+		OS::get_singleton()->benchmark_begin_measure("Servers", "XR");
+
+		xr_server = memnew(XRServer);
+
+		OS::get_singleton()->benchmark_end_measure("Servers", "XR");
+	}
+
+	OS::get_singleton()->benchmark_end_measure("Startup", "Servers");
 
 	register_core_singletons();
 
-	MAIN_PRINT("Main: Setup Logo");
+	/* Initialize the main window and boot screen */
+
+	{
+		OS::get_singleton()->benchmark_begin_measure("Startup", "Setup Window and Boot");
+
+		MAIN_PRINT("Main: Setup Logo");
 
 #if !defined(TOOLS_ENABLED) && (defined(WEB_ENABLED) || defined(ANDROID_ENABLED))
-	bool show_logo = false;
+		bool show_logo = false;
 #else
-	bool show_logo = true;
+		bool show_logo = true;
 #endif
 
-	if (init_windowed) {
-		//do none..
-	} else if (init_maximized) {
-		DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_MAXIMIZED);
-	} else if (init_fullscreen) {
-		DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_FULLSCREEN);
-	}
-	if (init_always_on_top) {
-		DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP, true);
-	}
+		if (init_windowed) {
+			//do none..
+		} else if (init_maximized) {
+			DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_MAXIMIZED);
+		} else if (init_fullscreen) {
+			DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_FULLSCREEN);
+		}
+		if (init_always_on_top) {
+			DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP, true);
+		}
 
-	MAIN_PRINT("Main: Load Boot Image");
+		MAIN_PRINT("Main: Load Boot Image");
 
-	Color clear = GLOBAL_DEF_BASIC("rendering/environment/defaults/default_clear_color", Color(0.3, 0.3, 0.3));
-	RenderingServer::get_singleton()->set_default_clear_color(clear);
+		Color clear = GLOBAL_DEF_BASIC("rendering/environment/defaults/default_clear_color", Color(0.3, 0.3, 0.3));
+		RenderingServer::get_singleton()->set_default_clear_color(clear);
 
-	if (show_logo) { //boot logo!
-		const bool boot_logo_image = GLOBAL_DEF_BASIC("application/boot_splash/show_image", true);
-		const String boot_logo_path = String(GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png"), String())).strip_edges();
-		const bool boot_logo_scale = GLOBAL_DEF_BASIC("application/boot_splash/fullsize", true);
-		const bool boot_logo_filter = GLOBAL_DEF_BASIC("application/boot_splash/use_filter", true);
+		if (show_logo) { //boot logo!
+			const bool boot_logo_image = GLOBAL_DEF_BASIC("application/boot_splash/show_image", true);
+			const String boot_logo_path = String(GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png"), String())).strip_edges();
+			const bool boot_logo_scale = GLOBAL_DEF_BASIC("application/boot_splash/fullsize", true);
+			const bool boot_logo_filter = GLOBAL_DEF_BASIC("application/boot_splash/use_filter", true);
 
-		Ref<Image> boot_logo;
+			Ref<Image> boot_logo;
 
-		if (boot_logo_image) {
-			if (!boot_logo_path.is_empty()) {
-				boot_logo.instantiate();
-				Error load_err = ImageLoader::load_image(boot_logo_path, boot_logo);
-				if (load_err) {
-					ERR_PRINT("Non-existing or invalid boot splash at '" + boot_logo_path + "'. Loading default splash.");
+			if (boot_logo_image) {
+				if (!boot_logo_path.is_empty()) {
+					boot_logo.instantiate();
+					Error load_err = ImageLoader::load_image(boot_logo_path, boot_logo);
+					if (load_err) {
+						ERR_PRINT("Non-existing or invalid boot splash at '" + boot_logo_path + "'. Loading default splash.");
+					}
 				}
+			} else {
+				// Create a 1×1 transparent image. This will effectively hide the splash image.
+				boot_logo.instantiate();
+				boot_logo->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
+				boot_logo->set_pixel(0, 0, Color(0, 0, 0, 0));
 			}
-		} else {
-			// Create a 1×1 transparent image. This will effectively hide the splash image.
-			boot_logo.instantiate();
-			boot_logo->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
-			boot_logo->set_pixel(0, 0, Color(0, 0, 0, 0));
-		}
 
-		Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color");
+			Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color");
 
 #if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
-		boot_bg_color =
-				GLOBAL_DEF_BASIC("application/boot_splash/bg_color",
-						(editor || project_manager) ? boot_splash_editor_bg_color : boot_splash_bg_color);
+			boot_bg_color =
+					GLOBAL_DEF_BASIC("application/boot_splash/bg_color",
+							(editor || project_manager) ? boot_splash_editor_bg_color : boot_splash_bg_color);
 #endif
-		if (boot_logo.is_valid()) {
-			RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale,
-					boot_logo_filter);
+			if (boot_logo.is_valid()) {
+				RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale,
+						boot_logo_filter);
 
-		} else {
+			} else {
 #ifndef NO_DEFAULT_BOOT_LOGO
-			MAIN_PRINT("Main: Create bootsplash");
+				MAIN_PRINT("Main: Create bootsplash");
 #if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
-			Ref<Image> splash = (editor || project_manager) ? memnew(Image(boot_splash_editor_png)) : memnew(Image(boot_splash_png));
+				Ref<Image> splash = (editor || project_manager) ? memnew(Image(boot_splash_editor_png)) : memnew(Image(boot_splash_png));
 #else
-			Ref<Image> splash = memnew(Image(boot_splash_png));
+				Ref<Image> splash = memnew(Image(boot_splash_png));
 #endif
 
-			MAIN_PRINT("Main: ClearColor");
-			RenderingServer::get_singleton()->set_default_clear_color(boot_bg_color);
-			MAIN_PRINT("Main: Image");
-			RenderingServer::get_singleton()->set_boot_image(splash, boot_bg_color, false);
+				MAIN_PRINT("Main: ClearColor");
+				RenderingServer::get_singleton()->set_default_clear_color(boot_bg_color);
+				MAIN_PRINT("Main: Image");
+				RenderingServer::get_singleton()->set_boot_image(splash, boot_bg_color, false);
 #endif
-		}
+			}
 
 #if defined(TOOLS_ENABLED) && defined(MACOS_ENABLED)
-		if (OS::get_singleton()->get_bundle_icon_path().is_empty()) {
-			Ref<Image> icon = memnew(Image(app_icon_png));
-			DisplayServer::get_singleton()->set_icon(icon);
-		}
+			if (OS::get_singleton()->get_bundle_icon_path().is_empty()) {
+				Ref<Image> icon = memnew(Image(app_icon_png));
+				DisplayServer::get_singleton()->set_icon(icon);
+			}
 #endif
-	}
+		}
 
-	DisplayServer::set_early_window_clear_color_override(false);
+		MAIN_PRINT("Main: Clear Color");
 
-	MAIN_PRINT("Main: DCC");
-	RenderingServer::get_singleton()->set_default_clear_color(
-			GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
+		DisplayServer::set_early_window_clear_color_override(false);
+		RenderingServer::get_singleton()->set_default_clear_color(
+				GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
 
-	GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg"), String());
-	GLOBAL_DEF(PropertyInfo(Variant::STRING, "application/config/macos_native_icon", PROPERTY_HINT_FILE, "*.icns"), String());
-	GLOBAL_DEF(PropertyInfo(Variant::STRING, "application/config/windows_native_icon", PROPERTY_HINT_FILE, "*.ico"), String());
+		GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg"), String());
+		GLOBAL_DEF(PropertyInfo(Variant::STRING, "application/config/macos_native_icon", PROPERTY_HINT_FILE, "*.icns"), String());
+		GLOBAL_DEF(PropertyInfo(Variant::STRING, "application/config/windows_native_icon", PROPERTY_HINT_FILE, "*.ico"), String());
 
-	Input *id = Input::get_singleton();
-	if (id) {
-		agile_input_event_flushing = GLOBAL_DEF("input_devices/buffering/agile_event_flushing", false);
+		MAIN_PRINT("Main: Touch Input");
 
-		if (bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_touch_from_mouse", false)) &&
-				!(editor || project_manager)) {
-			if (!DisplayServer::get_singleton()->is_touchscreen_available()) {
-				//only if no touchscreen ui hint, set emulation
-				id->set_emulate_touch_from_mouse(true);
+		Input *id = Input::get_singleton();
+		if (id) {
+			agile_input_event_flushing = GLOBAL_DEF("input_devices/buffering/agile_event_flushing", false);
+
+			if (bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_touch_from_mouse", false)) &&
+					!(editor || project_manager)) {
+				if (!DisplayServer::get_singleton()->is_touchscreen_available()) {
+					//only if no touchscreen ui hint, set emulation
+					id->set_emulate_touch_from_mouse(true);
+				}
 			}
+
+			id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
 		}
 
-		id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
-	}
+		GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
+		GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
 
-	GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
-	GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
+		OS::get_singleton()->benchmark_end_measure("Startup", "Setup Window and Boot");
+	}
 
 	MAIN_PRINT("Main: Load Translations and Remaps");
 
-	translation_server->setup(); //register translations, load them, etc.
-	if (!locale.is_empty()) {
-		translation_server->set_locale(locale);
-	}
-	translation_server->load_translations();
-	ResourceLoader::load_translation_remaps(); //load remaps for resources
-
-	ResourceLoader::load_path_remaps();
+	/* Setup translations and remaps */
 
-	MAIN_PRINT("Main: Load TextServer");
+	{
+		OS::get_singleton()->benchmark_begin_measure("Startup", "Translations and Remaps");
 
-	/* Enum text drivers */
-	GLOBAL_DEF_RST("internationalization/rendering/text_driver", "");
-	String text_driver_options;
-	for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
-		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 += ",";
+		translation_server->setup(); //register translations, load them, etc.
+		if (!locale.is_empty()) {
+			translation_server->set_locale(locale);
 		}
-		text_driver_options += driver_name;
-	}
-	ProjectSettings::get_singleton()->set_custom_property_info(PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options));
+		translation_server->load_translations();
+		ResourceLoader::load_translation_remaps(); //load remaps for resources
 
-	/* Determine text driver */
-	if (text_driver.is_empty()) {
-		text_driver = GLOBAL_GET("internationalization/rendering/text_driver");
+		ResourceLoader::load_path_remaps();
+
+		OS::get_singleton()->benchmark_end_measure("Startup", "Translations and Remaps");
 	}
 
-	if (!text_driver.is_empty()) {
-		/* Load user selected text server. */
+	MAIN_PRINT("Main: Load TextServer");
+
+	/* Setup Text Server */
+
+	{
+		OS::get_singleton()->benchmark_begin_measure("Startup", "Text Server");
+
+		/* Enum text drivers */
+		GLOBAL_DEF_RST("internationalization/rendering/text_driver", "");
+		String text_driver_options;
 		for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
-			if (TextServerManager::get_singleton()->get_interface(i)->get_name() == text_driver) {
-				text_driver_idx = i;
-				break;
+			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 += driver_name;
 		}
-	}
+		ProjectSettings::get_singleton()->set_custom_property_info(PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options));
 
-	if (text_driver_idx < 0) {
-		/* If not selected, use one with the most features available. */
-		int max_features = 0;
-		for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
-			uint32_t features = TextServerManager::get_singleton()->get_interface(i)->get_features();
-			int feature_number = 0;
-			while (features) {
-				feature_number += features & 1;
-				features >>= 1;
+		/* Determine text driver */
+		if (text_driver.is_empty()) {
+			text_driver = GLOBAL_GET("internationalization/rendering/text_driver");
+		}
+
+		if (!text_driver.is_empty()) {
+			/* Load user selected text server. */
+			for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+				if (TextServerManager::get_singleton()->get_interface(i)->get_name() == text_driver) {
+					text_driver_idx = i;
+					break;
+				}
 			}
-			if (feature_number >= max_features) {
-				max_features = feature_number;
-				text_driver_idx = i;
+		}
+
+		if (text_driver_idx < 0) {
+			/* If not selected, use one with the most features available. */
+			int max_features = 0;
+			for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+				uint32_t features = TextServerManager::get_singleton()->get_interface(i)->get_features();
+				int feature_number = 0;
+				while (features) {
+					feature_number += features & 1;
+					features >>= 1;
+				}
+				if (feature_number >= max_features) {
+					max_features = feature_number;
+					text_driver_idx = i;
+				}
 			}
 		}
-	}
-	if (text_driver_idx >= 0) {
-		Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(text_driver_idx);
-		TextServerManager::get_singleton()->set_primary_interface(ts);
-		if (ts->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
-			ts->load_support_data("res://" + ts->get_support_data_filename());
+		if (text_driver_idx >= 0) {
+			Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(text_driver_idx);
+			TextServerManager::get_singleton()->set_primary_interface(ts);
+			if (ts->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
+				ts->load_support_data("res://" + ts->get_support_data_filename());
+			}
+		} else {
+			ERR_FAIL_V_MSG(ERR_CANT_CREATE, "TextServer: Unable to create TextServer interface.");
 		}
-	} else {
-		ERR_FAIL_V_MSG(ERR_CANT_CREATE, "TextServer: Unable to create TextServer interface.");
-	}
 
-	OS::get_singleton()->benchmark_end_measure("Startup", "Servers");
+		OS::get_singleton()->benchmark_end_measure("Startup", "Text Server");
+	}
 
 	MAIN_PRINT("Main: Load Scene Types");
 
@@ -2691,23 +2760,42 @@ Error Main::setup2() {
 
 	register_scene_singletons();
 
-	initialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);
-	GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);
+	{
+		OS::get_singleton()->benchmark_begin_measure("Scene", "Modules and Extensions");
+
+		initialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);
+		GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);
+
+		OS::get_singleton()->benchmark_end_measure("Scene", "Modules and Extensions");
+	}
+
+	OS::get_singleton()->benchmark_end_measure("Startup", "Scene");
 
 #ifdef TOOLS_ENABLED
 	ClassDB::set_current_api(ClassDB::API_EDITOR);
 	register_editor_types();
-	initialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR);
-	GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR);
+
+	{
+		OS::get_singleton()->benchmark_begin_measure("Editor", "Modules and Extensions");
+
+		initialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR);
+		GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR);
+
+		OS::get_singleton()->benchmark_end_measure("Editor", "Modules and Extensions");
+	}
 
 	ClassDB::set_current_api(ClassDB::API_CORE);
 
 #endif
 
-	MAIN_PRINT("Main: Load Modules");
+	MAIN_PRINT("Main: Load Platforms");
+
+	OS::get_singleton()->benchmark_begin_measure("Startup", "Platforms");
 
 	register_platform_apis();
 
+	OS::get_singleton()->benchmark_end_measure("Startup", "Platforms");
+
 	GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/mouse_cursor/custom_image", PROPERTY_HINT_FILE, "*.png,*.webp"), String());
 	GLOBAL_DEF_BASIC("display/mouse_cursor/custom_image_hotspot", Vector2());
 	GLOBAL_DEF_BASIC("display/mouse_cursor/tooltip_position_offset", Point2(10, 10));
@@ -2721,12 +2809,18 @@ Error Main::setup2() {
 		}
 	}
 
+	OS::get_singleton()->benchmark_begin_measure("Startup", "Finalize Setup");
+
 	camera_server = CameraServer::create();
 
 	MAIN_PRINT("Main: Load Physics");
 
 	initialize_physics();
+
+	MAIN_PRINT("Main: Load Navigation");
+
 	initialize_navigation_server();
+
 	register_server_singletons();
 
 	// This loads global classes, so it must happen before custom loaders and savers are registered
@@ -2758,6 +2852,8 @@ Error Main::setup2() {
 		rendering_server->global_shader_parameters_load_settings(!editor);
 	}
 
+	OS::get_singleton()->benchmark_end_measure("Startup", "Finalize Setup");
+
 	_start_success = true;
 
 	ClassDB::set_current_api(ClassDB::API_NONE); //no more APIs are registered at this point
@@ -2766,7 +2862,7 @@ Error Main::setup2() {
 	print_verbose("EDITOR API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_EDITOR)));
 	MAIN_PRINT("Main: Done");
 
-	OS::get_singleton()->benchmark_end_measure("Startup", "Scene");
+	OS::get_singleton()->benchmark_end_measure("Startup", "Setup");
 
 	return OK;
 }