1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-20 14:45:44 +00:00

Add some important profiling hooks.

This commit is contained in:
Lukas Tenbrink
2025-04-01 19:00:57 +02:00
parent e80194e31f
commit c3747884da
14 changed files with 118 additions and 10 deletions

View File

@@ -30,7 +30,13 @@
#include "profiling.h" #include "profiling.h"
#ifdef GODOT_USE_PERFETTO #if defined(GODOT_USE_TRACY)
void godot_init_profiler() {
// Send our first event to tracy; otherwise it doesn't start collecting data.
// FrameMark is kind of fitting because it communicates "this is where we started tracing".
FrameMark;
}
#elif defined(GODOT_USE_PERFETTO)
PERFETTO_TRACK_EVENT_STATIC_STORAGE(); PERFETTO_TRACK_EVENT_STATIC_STORAGE();
void godot_init_profiler() { void godot_init_profiler() {
@@ -41,5 +47,8 @@ void godot_init_profiler() {
perfetto::Tracing::Initialize(args); perfetto::Tracing::Initialize(args);
perfetto::TrackEvent::Register(); perfetto::TrackEvent::Register();
} }
#else
void godot_init_profiler() {
// Stub
}
#endif #endif

View File

@@ -53,11 +53,7 @@
static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location, TracyLine){ m_zone_name, TracyFunction, TracyFile, (uint32_t)TracyLine, 0 }; \ static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location, TracyLine){ m_zone_name, TracyFunction, TracyFile, (uint32_t)TracyLine, 0 }; \
new (&__godot_tracy_zone_##m_group_name) tracy::ScopedZone(&TracyConcat(__tracy_source_location, TracyLine), TRACY_CALLSTACK, true) new (&__godot_tracy_zone_##m_group_name) tracy::ScopedZone(&TracyConcat(__tracy_source_location, TracyLine), TRACY_CALLSTACK, true)
static void godot_init_profiler() { void godot_init_profiler();
// Send our first event to tracy; otherwise it doesn't start collecting data.
// FrameMark is kind of fitting because it communicates "this is where we started tracing".
FrameMark;
}
#elif defined(GODOT_USE_PERFETTO) #elif defined(GODOT_USE_PERFETTO)
// Use the perfetto profiler. // Use the perfetto profiler.
@@ -94,8 +90,7 @@ void godot_init_profiler();
#else #else
// No profiling; all macros are stubs. // No profiling; all macros are stubs.
static void godot_init_profiler() { void godot_init_profiler();
}
#define GodotProfileFrameMark #define GodotProfileFrameMark
#define GodotProfileZone(m_zone_name) #define GodotProfileZone(m_zone_name)

View File

@@ -41,6 +41,7 @@
#include "core/io/dir_access.h" #include "core/io/dir_access.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
#include "core/os/main_loop.h" #include "core/os/main_loop.h"
#include "core/profiling/profiling.h"
#import "drivers/apple/os_log_logger.h" #import "drivers/apple/os_log_logger.h"
#include "main/main.h" #include "main/main.h"
@@ -205,6 +206,9 @@ bool OS_AppleEmbedded::iterate() {
return true; return true;
} }
GodotProfileFrameMark;
GodotProfileZone("OS_AppleEmbedded::iterate");
if (DisplayServer::get_singleton()) { if (DisplayServer::get_singleton()) {
DisplayServer::get_singleton()->process_events(); DisplayServer::get_singleton()->process_events();
} }

View File

@@ -50,6 +50,7 @@
#include "core/object/script_language.h" #include "core/object/script_language.h"
#include "core/os/os.h" #include "core/os/os.h"
#include "core/os/time.h" #include "core/os/time.h"
#include "core/profiling/profiling.h"
#include "core/register_core_types.h" #include "core/register_core_types.h"
#include "core/string/translation_server.h" #include "core/string/translation_server.h"
#include "core/version.h" #include "core/version.h"
@@ -975,6 +976,7 @@ int Main::test_entrypoint(int argc, char *argv[], bool &tests_need_run) {
*/ */
Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_phase) { Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_phase) {
GodotProfileZone("setup");
Thread::make_main_thread(); Thread::make_main_thread();
set_current_thread_safe_for_nodes(true); set_current_thread_safe_for_nodes(true);
@@ -2852,6 +2854,7 @@ Error _parse_resource_dummy(void *p_data, VariantParser::Stream *p_stream, Ref<R
} }
Error Main::setup2(bool p_show_boot_logo) { Error Main::setup2(bool p_show_boot_logo) {
GodotProfileZone("setup2");
OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Setup2"); OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Setup2");
Thread::make_main_thread(); // Make whatever thread call this the main thread. Thread::make_main_thread(); // Make whatever thread call this the main thread.
@@ -3687,6 +3690,7 @@ Error Main::setup2(bool p_show_boot_logo) {
} }
void Main::setup_boot_logo() { void Main::setup_boot_logo() {
GodotProfileZone("setup_boot_logo");
MAIN_PRINT("Main: Load Boot Image"); MAIN_PRINT("Main: Load Boot Image");
#if !defined(TOOLS_ENABLED) && defined(WEB_ENABLED) #if !defined(TOOLS_ENABLED) && defined(WEB_ENABLED)
@@ -3782,6 +3786,7 @@ static MainTimerSync main_timer_sync;
// and should move on to `OS::run`, and EXIT_FAILURE otherwise for // and should move on to `OS::run`, and EXIT_FAILURE otherwise for
// an early exit with that error code. // an early exit with that error code.
int Main::start() { int Main::start() {
GodotProfileZone("start");
OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Start"); OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Start");
ERR_FAIL_COND_V(!_start_success, EXIT_FAILURE); ERR_FAIL_COND_V(!_start_success, EXIT_FAILURE);
@@ -4641,6 +4646,8 @@ static uint64_t navigation_process_max = 0;
// will terminate the program. In case of failure, the OS exit code needs // will terminate the program. In case of failure, the OS exit code needs
// to be set explicitly here (defaults to EXIT_SUCCESS). // to be set explicitly here (defaults to EXIT_SUCCESS).
bool Main::iteration() { bool Main::iteration() {
GodotProfileZone("Main::iteration");
GodotProfileZoneGroupedFirst(_profile_zone, "prepare");
iterating++; iterating++;
const uint64_t ticks = OS::get_singleton()->get_ticks_usec(); const uint64_t ticks = OS::get_singleton()->get_ticks_usec();
@@ -4686,6 +4693,8 @@ bool Main::iteration() {
#endif // XR_DISABLED #endif // XR_DISABLED
for (int iters = 0; iters < advance.physics_steps; ++iters) { for (int iters = 0; iters < advance.physics_steps; ++iters) {
GodotProfileZone("Physics Step");
GodotProfileZoneGroupedFirst(_physics_zone, "setup");
if (Input::get_singleton()->is_agile_input_event_flushing()) { if (Input::get_singleton()->is_agile_input_event_flushing()) {
Input::get_singleton()->flush_buffered_events(); Input::get_singleton()->flush_buffered_events();
} }
@@ -4698,18 +4707,22 @@ bool Main::iteration() {
// Prepare the fixed timestep interpolated nodes BEFORE they are updated // Prepare the fixed timestep interpolated nodes BEFORE they are updated
// by the physics server, otherwise the current and previous transforms // by the physics server, otherwise the current and previous transforms
// may be the same, and no interpolation takes place. // may be the same, and no interpolation takes place.
GodotProfileZoneGrouped(_physics_zone, "main loop iteration prepare");
OS::get_singleton()->get_main_loop()->iteration_prepare(); OS::get_singleton()->get_main_loop()->iteration_prepare();
#ifndef PHYSICS_3D_DISABLED #ifndef PHYSICS_3D_DISABLED
GodotProfileZoneGrouped(_physics_zone, "PhysicsServer3D::sync");
PhysicsServer3D::get_singleton()->sync(); PhysicsServer3D::get_singleton()->sync();
PhysicsServer3D::get_singleton()->flush_queries(); PhysicsServer3D::get_singleton()->flush_queries();
#endif // PHYSICS_3D_DISABLED #endif // PHYSICS_3D_DISABLED
#ifndef PHYSICS_2D_DISABLED #ifndef PHYSICS_2D_DISABLED
GodotProfileZoneGrouped(_physics_zone, "PhysicsServer2D::sync");
PhysicsServer2D::get_singleton()->sync(); PhysicsServer2D::get_singleton()->sync();
PhysicsServer2D::get_singleton()->flush_queries(); PhysicsServer2D::get_singleton()->flush_queries();
#endif // PHYSICS_2D_DISABLED #endif // PHYSICS_2D_DISABLED
GodotProfileZoneGrouped(_physics_zone, "physics_process");
if (OS::get_singleton()->get_main_loop()->physics_process(physics_step * time_scale)) { if (OS::get_singleton()->get_main_loop()->physics_process(physics_step * time_scale)) {
#ifndef PHYSICS_3D_DISABLED #ifndef PHYSICS_3D_DISABLED
PhysicsServer3D::get_singleton()->end_sync(); PhysicsServer3D::get_singleton()->end_sync();
@@ -4727,9 +4740,11 @@ bool Main::iteration() {
uint64_t navigation_begin = OS::get_singleton()->get_ticks_usec(); uint64_t navigation_begin = OS::get_singleton()->get_ticks_usec();
#ifndef NAVIGATION_2D_DISABLED #ifndef NAVIGATION_2D_DISABLED
GodotProfileZoneGrouped(_profile_zone, "NavigationServer2D::physics_process");
NavigationServer2D::get_singleton()->physics_process(physics_step * time_scale); NavigationServer2D::get_singleton()->physics_process(physics_step * time_scale);
#endif // NAVIGATION_2D_DISABLED #endif // NAVIGATION_2D_DISABLED
#ifndef NAVIGATION_3D_DISABLED #ifndef NAVIGATION_3D_DISABLED
GodotProfileZoneGrouped(_profile_zone, "NavigationServer3D::physics_process");
NavigationServer3D::get_singleton()->physics_process(physics_step * time_scale); NavigationServer3D::get_singleton()->physics_process(physics_step * time_scale);
#endif // NAVIGATION_3D_DISABLED #endif // NAVIGATION_3D_DISABLED
@@ -4740,17 +4755,20 @@ bool Main::iteration() {
#endif // !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED) #endif // !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
#ifndef PHYSICS_3D_DISABLED #ifndef PHYSICS_3D_DISABLED
GodotProfileZoneGrouped(_profile_zone, "3D physics");
PhysicsServer3D::get_singleton()->end_sync(); PhysicsServer3D::get_singleton()->end_sync();
PhysicsServer3D::get_singleton()->step(physics_step * time_scale); PhysicsServer3D::get_singleton()->step(physics_step * time_scale);
#endif // PHYSICS_3D_DISABLED #endif // PHYSICS_3D_DISABLED
#ifndef PHYSICS_2D_DISABLED #ifndef PHYSICS_2D_DISABLED
GodotProfileZoneGrouped(_profile_zone, "2D physics");
PhysicsServer2D::get_singleton()->end_sync(); PhysicsServer2D::get_singleton()->end_sync();
PhysicsServer2D::get_singleton()->step(physics_step * time_scale); PhysicsServer2D::get_singleton()->step(physics_step * time_scale);
#endif // PHYSICS_2D_DISABLED #endif // PHYSICS_2D_DISABLED
message_queue->flush(); message_queue->flush();
GodotProfileZoneGrouped(_profile_zone, "main loop iteration end");
OS::get_singleton()->get_main_loop()->iteration_end(); OS::get_singleton()->get_main_loop()->iteration_end();
physics_process_ticks = MAX(physics_process_ticks, OS::get_singleton()->get_ticks_usec() - physics_begin); // keep the largest one for reference physics_process_ticks = MAX(physics_process_ticks, OS::get_singleton()->get_ticks_usec() - physics_begin); // keep the largest one for reference
@@ -4765,20 +4783,25 @@ bool Main::iteration() {
uint64_t process_begin = OS::get_singleton()->get_ticks_usec(); uint64_t process_begin = OS::get_singleton()->get_ticks_usec();
GodotProfileZoneGrouped(_profile_zone, "process");
if (OS::get_singleton()->get_main_loop()->process(process_step * time_scale)) { if (OS::get_singleton()->get_main_loop()->process(process_step * time_scale)) {
exit = true; exit = true;
} }
message_queue->flush(); message_queue->flush();
#ifndef NAVIGATION_2D_DISABLED #ifndef NAVIGATION_2D_DISABLED
GodotProfileZoneGrouped(_profile_zone, "process 2D navigation");
NavigationServer2D::get_singleton()->process(process_step * time_scale); NavigationServer2D::get_singleton()->process(process_step * time_scale);
#endif // NAVIGATION_2D_DISABLED #endif // NAVIGATION_2D_DISABLED
#ifndef NAVIGATION_3D_DISABLED #ifndef NAVIGATION_3D_DISABLED
GodotProfileZoneGrouped(_profile_zone, "process 3D navigation");
NavigationServer3D::get_singleton()->process(process_step * time_scale); NavigationServer3D::get_singleton()->process(process_step * time_scale);
#endif // NAVIGATION_3D_DISABLED #endif // NAVIGATION_3D_DISABLED
GodotProfileZoneGrouped(_profile_zone, "RenderingServer::sync");
RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames. RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames.
GodotProfileZoneGrouped(_profile_zone, "RenderingServer::draw");
const bool has_pending_resources_for_processing = RD::get_singleton() && RD::get_singleton()->has_pending_resources_for_processing(); const bool has_pending_resources_for_processing = RD::get_singleton() && RD::get_singleton()->has_pending_resources_for_processing();
bool wants_present = (DisplayServer::get_singleton()->can_any_window_draw() || bool wants_present = (DisplayServer::get_singleton()->can_any_window_draw() ||
DisplayServer::get_singleton()->has_additional_outputs()) && DisplayServer::get_singleton()->has_additional_outputs()) &&
@@ -4802,12 +4825,15 @@ bool Main::iteration() {
process_max = MAX(process_ticks, process_max); process_max = MAX(process_ticks, process_max);
uint64_t frame_time = OS::get_singleton()->get_ticks_usec() - ticks; uint64_t frame_time = OS::get_singleton()->get_ticks_usec() - ticks;
GodotProfileZoneGrouped(_profile_zone, "GDExtensionManager::frame");
GDExtensionManager::get_singleton()->frame(); GDExtensionManager::get_singleton()->frame();
GodotProfileZoneGrouped(_profile_zone, "ScriptServer::frame");
for (int i = 0; i < ScriptServer::get_language_count(); i++) { for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptServer::get_language(i)->frame(); ScriptServer::get_language(i)->frame();
} }
GodotProfileZoneGrouped(_profile_zone, "AudioServer::update");
AudioServer::get_singleton()->update(); AudioServer::get_singleton()->update();
if (EngineDebugger::is_active()) { if (EngineDebugger::is_active()) {
@@ -4846,6 +4872,7 @@ bool Main::iteration() {
iterating--; iterating--;
if (movie_writer) { if (movie_writer) {
GodotProfileZoneGrouped(_profile_zone, "movie_writer->add_frame");
movie_writer->add_frame(); movie_writer->add_frame();
} }
@@ -4872,6 +4899,7 @@ bool Main::iteration() {
SceneTree *scene_tree = SceneTree::get_singleton(); SceneTree *scene_tree = SceneTree::get_singleton();
bool wake_for_events = scene_tree && scene_tree->is_accessibility_enabled(); bool wake_for_events = scene_tree && scene_tree->is_accessibility_enabled();
GodotProfileZoneGrouped(_profile_zone, "OS::add_frame_delay");
OS::get_singleton()->add_frame_delay(DisplayServer::get_singleton()->window_can_draw(), wake_for_events); OS::get_singleton()->add_frame_delay(DisplayServer::get_singleton()->window_can_draw(), wake_for_events);
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
@@ -4911,6 +4939,7 @@ void Main::force_redraw() {
* The order matters as some of those steps are linked with each other. * The order matters as some of those steps are linked with each other.
*/ */
void Main::cleanup(bool p_force) { void Main::cleanup(bool p_force) {
GodotProfileZone("cleanup");
OS::get_singleton()->benchmark_begin_measure("Shutdown", "Main::Cleanup"); OS::get_singleton()->benchmark_begin_measure("Shutdown", "Main::Cleanup");
if (!p_force) { if (!p_force) {
ERR_FAIL_COND(!_start_success); ERR_FAIL_COND(!_start_success);

View File

@@ -42,6 +42,7 @@
#include "core/extension/gdextension_manager.h" #include "core/extension/gdextension_manager.h"
#include "core/io/xml_parser.h" #include "core/io/xml_parser.h"
#include "core/os/main_loop.h" #include "core/os/main_loop.h"
#include "core/profiling/profiling.h"
#include "drivers/unix/dir_access_unix.h" #include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h" #include "drivers/unix/file_access_unix.h"
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
@@ -356,6 +357,8 @@ void OS_Android::main_loop_begin() {
} }
bool OS_Android::main_loop_iterate(bool *r_should_swap_buffers) { bool OS_Android::main_loop_iterate(bool *r_should_swap_buffers) {
GodotProfileFrameMark;
GodotProfileZone("OS_Android::main_loop_iterate");
if (!main_loop) { if (!main_loop) {
return false; return false;
} }

View File

@@ -37,6 +37,7 @@
#ifdef SDL_ENABLED #ifdef SDL_ENABLED
#include "drivers/sdl/joypad_sdl.h" #include "drivers/sdl/joypad_sdl.h"
#endif #endif
#include "core/profiling/profiling.h"
#include "main/main.h" #include "main/main.h"
#include "servers/display/display_server.h" #include "servers/display/display_server.h"
#include "servers/rendering/rendering_server.h" #include "servers/rendering/rendering_server.h"
@@ -970,6 +971,8 @@ String OS_LinuxBSD::get_system_dir(SystemDir p_dir, bool p_shared_storage) const
} }
void OS_LinuxBSD::run() { void OS_LinuxBSD::run() {
GodotProfileFrameMark;
GodotProfileZone("OS_LinuxBSD::run");
if (!main_loop) { if (!main_loop) {
return; return;
} }

View File

@@ -34,6 +34,7 @@
#import "godot_window.h" #import "godot_window.h"
#import "key_mapping_macos.h" #import "key_mapping_macos.h"
#include "core/profiling/profiling.h"
#include "main/main.h" #include "main/main.h"
@implementation GodotContentLayerDelegate @implementation GodotContentLayerDelegate
@@ -56,6 +57,9 @@
- (void)displayLayer:(CALayer *)layer { - (void)displayLayer:(CALayer *)layer {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (OS::get_singleton()->get_main_loop() && ds->get_is_resizing() && need_redraw) { if (OS::get_singleton()->get_main_loop() && ds->get_is_resizing() && need_redraw) {
GodotProfileFrameMark;
GodotProfileZone("[GodotContentLayerDelegate displayLayer]");
Main::force_redraw(); Main::force_redraw();
if (!Main::is_iterating()) { // Avoid cyclic loop. if (!Main::is_iterating()) { // Avoid cyclic loop.
Main::iteration(); Main::iteration();

View File

@@ -1106,6 +1106,9 @@ void OS_MacOS_NSApp::start_main() {
pre_wait_observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { pre_wait_observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
@autoreleasepool { @autoreleasepool {
@try { @try {
GodotProfileFrameMark;
GodotProfileZone("macOS main loop");
if (ds_mac) { if (ds_mac) {
ds_mac->_process_events(false); ds_mac->_process_events(false);
} else if (ds) { } else if (ds) {
@@ -1279,6 +1282,9 @@ void OS_MacOS_Embedded::run() {
while (true) { while (true) {
@autoreleasepool { @autoreleasepool {
@try { @try {
GodotProfileFrameMark;
GodotProfileZone("macOS embedded main loop");
ds->process_events(); ds->process_events();
#ifdef SDL_ENABLED #ifdef SDL_ENABLED

View File

@@ -40,6 +40,7 @@
#include "core/debugger/engine_debugger.h" #include "core/debugger/engine_debugger.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
#include "core/os/main_loop.h" #include "core/os/main_loop.h"
#include "core/profiling/profiling.h"
#include "drivers/unix/dir_access_unix.h" #include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h" #include "drivers/unix/file_access_unix.h"
#include "main/main.h" #include "main/main.h"
@@ -79,6 +80,8 @@ void OS_Web::fs_sync_callback() {
} }
bool OS_Web::main_loop_iterate() { bool OS_Web::main_loop_iterate() {
GodotProfileFrameMark;
GodotProfileZone("OS_Web::main_loop_iterate");
if (is_userfs_persistent() && idb_needs_sync && !idb_is_syncing) { if (is_userfs_persistent() && idb_needs_sync && !idb_is_syncing) {
idb_is_syncing = true; idb_is_syncing = true;
idb_needs_sync = false; idb_needs_sync = false;

View File

@@ -39,6 +39,7 @@
#include "core/debugger/script_debugger.h" #include "core/debugger/script_debugger.h"
#include "core/io/marshalls.h" #include "core/io/marshalls.h"
#include "core/os/main_loop.h" #include "core/os/main_loop.h"
#include "core/profiling/profiling.h"
#include "core/version_generated.gen.h" #include "core/version_generated.gen.h"
#include "drivers/windows/dir_access_windows.h" #include "drivers/windows/dir_access_windows.h"
#include "drivers/windows/file_access_windows.h" #include "drivers/windows/file_access_windows.h"
@@ -2329,6 +2330,8 @@ void OS_Windows::run() {
main_loop->initialize(); main_loop->initialize();
while (true) { while (true) {
GodotProfileFrameMark;
GodotProfileZone("OS_Windows::run");
DisplayServer::get_singleton()->process_events(); // get rid of pending events DisplayServer::get_singleton()->process_events(); // get rid of pending events
if (Main::iteration()) { if (Main::iteration()) {
break; break;

View File

@@ -37,6 +37,7 @@
#include "core/object/message_queue.h" #include "core/object/message_queue.h"
#include "core/object/worker_thread_pool.h" #include "core/object/worker_thread_pool.h"
#include "core/os/os.h" #include "core/os/os.h"
#include "core/profiling/profiling.h"
#include "node.h" #include "node.h"
#include "scene/animation/tween.h" #include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h" #include "scene/debugger/scene_debugger.h"
@@ -572,6 +573,7 @@ void SceneTree::set_group(const StringName &p_group, const String &p_name, const
} }
void SceneTree::initialize() { void SceneTree::initialize() {
GodotProfileZone("SceneTree::initialize");
ERR_FAIL_NULL(root); ERR_FAIL_NULL(root);
MainLoop::initialize(); MainLoop::initialize();
root->_set_tree(this); root->_set_tree(this);

View File

@@ -33,6 +33,7 @@
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
#include "core/math/transform_interpolator.h" #include "core/math/transform_interpolator.h"
#include "core/object/worker_thread_pool.h" #include "core/object/worker_thread_pool.h"
#include "core/profiling/profiling.h"
#include "renderer_canvas_cull.h" #include "renderer_canvas_cull.h"
#include "renderer_scene_cull.h" #include "renderer_scene_cull.h"
#include "rendering_server_globals.h" #include "rendering_server_globals.h"
@@ -733,6 +734,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
} }
void RendererViewport::draw_viewports(bool p_swap_buffers) { void RendererViewport::draw_viewports(bool p_swap_buffers) {
GodotProfileZoneGroupedFirst(_profile_zone, "prepare viewports");
timestamp_vp_map.clear(); timestamp_vp_map.clear();
#ifndef XR_DISABLED #ifndef XR_DISABLED
@@ -750,6 +752,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
} }
if (sorted_active_viewports_dirty) { if (sorted_active_viewports_dirty) {
GodotProfileZoneGrouped(_profile_zone, "_sort_active_viewports");
sorted_active_viewports = _sort_active_viewports(); sorted_active_viewports = _sort_active_viewports();
sorted_active_viewports_dirty = false; sorted_active_viewports_dirty = false;
} }
@@ -758,11 +761,12 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
//draw viewports //draw viewports
RENDER_TIMESTAMP("> Render Viewports"); RENDER_TIMESTAMP("> Render Viewports");
GodotProfileZoneGrouped(_profile_zone, "render viewports");
//determine what is visible //determine what is visible
draw_viewports_pass++; draw_viewports_pass++;
for (int i = sorted_active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order for (int i = sorted_active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
Viewport *vp = sorted_active_viewports[i]; Viewport *vp = sorted_active_viewports[i];
if (vp->update_mode == RS::VIEWPORT_UPDATE_DISABLED) { if (vp->update_mode == RS::VIEWPORT_UPDATE_DISABLED) {
@@ -821,6 +825,9 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
int draw_calls_used = 0; int draw_calls_used = 0;
for (int i = 0; i < sorted_active_viewports.size(); i++) { for (int i = 0; i < sorted_active_viewports.size(); i++) {
// TODO Somehow print the index
GodotProfileZone("render viewport");
Viewport *vp = sorted_active_viewports[i]; Viewport *vp = sorted_active_viewports[i];
if (vp->last_pass != draw_viewports_pass) { if (vp->last_pass != draw_viewports_pass) {
@@ -925,6 +932,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
vertices_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_CANVAS][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME]; vertices_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_CANVAS][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME];
draw_calls_used += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_CANVAS][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME]; draw_calls_used += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_CANVAS][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME];
} }
RSG::scene->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED); RSG::scene->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED);
total_objects_drawn = objects_drawn; total_objects_drawn = objects_drawn;
@@ -933,6 +941,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
RENDER_TIMESTAMP("< Render Viewports"); RENDER_TIMESTAMP("< Render Viewports");
GodotProfileZoneGrouped(_profile_zone, "rasterizer->blit_render_targets_to_screen");
if (p_swap_buffers && !blit_to_screen_list.is_empty()) { if (p_swap_buffers && !blit_to_screen_list.is_empty()) {
for (const KeyValue<int, Vector<BlitToScreen>> &E : blit_to_screen_list) { for (const KeyValue<int, Vector<BlitToScreen>> &E : blit_to_screen_list) {
RSG::rasterizer->blit_render_targets_to_screen(E.key, E.value.ptr(), E.value.size()); RSG::rasterizer->blit_render_targets_to_screen(E.key, E.value.ptr(), E.value.size());

View File

@@ -37,6 +37,7 @@
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
#include "core/io/dir_access.h" #include "core/io/dir_access.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
#include "core/profiling/profiling.h"
#include "modules/modules_enabled.gen.h" #include "modules/modules_enabled.gen.h"
#include "servers/rendering/rendering_shader_container.h" #include "servers/rendering/rendering_shader_container.h"
@@ -6256,12 +6257,16 @@ String RenderingDevice::get_device_pipeline_cache_uuid() const {
void RenderingDevice::swap_buffers(bool p_present) { void RenderingDevice::swap_buffers(bool p_present) {
ERR_RENDER_THREAD_GUARD(); ERR_RENDER_THREAD_GUARD();
GodotProfileZoneGroupedFirst(_profile_zone, "_end_frame");
_end_frame(); _end_frame();
GodotProfileZoneGrouped(_profile_zone, "_execute_frame");
_execute_frame(p_present); _execute_frame(p_present);
// Advance to the next frame and begin recording again. // Advance to the next frame and begin recording again.
frame = (frame + 1) % frames.size(); frame = (frame + 1) % frames.size();
GodotProfileZoneGrouped(_profile_zone, "_begin_frame");
_begin_frame(true); _begin_frame(true);
} }
@@ -6389,27 +6394,34 @@ uint64_t RenderingDevice::get_memory_usage(MemoryType p_type) const {
} }
void RenderingDevice::_begin_frame(bool p_presented) { void RenderingDevice::_begin_frame(bool p_presented) {
GodotProfileZoneGroupedFirst(_profile_zone, "_stall_for_frame");
// Before writing to this frame, wait for it to be finished. // Before writing to this frame, wait for it to be finished.
_stall_for_frame(frame); _stall_for_frame(frame);
if (command_pool_reset_enabled) { if (command_pool_reset_enabled) {
GodotProfileZoneGrouped(_profile_zone, "driver->command_pool_reset");
bool reset = driver->command_pool_reset(frames[frame].command_pool); bool reset = driver->command_pool_reset(frames[frame].command_pool);
ERR_FAIL_COND(!reset); ERR_FAIL_COND(!reset);
} }
if (p_presented) { if (p_presented) {
GodotProfileZoneGrouped(_profile_zone, "update_perf_report");
update_perf_report(); update_perf_report();
driver->linear_uniform_set_pools_reset(frame); driver->linear_uniform_set_pools_reset(frame);
} }
// Begin recording on the frame's command buffers. // Begin recording on the frame's command buffers.
GodotProfileZoneGrouped(_profile_zone, "driver->begin_segment");
driver->begin_segment(frame, frames_drawn++); driver->begin_segment(frame, frames_drawn++);
GodotProfileZoneGrouped(_profile_zone, "driver->command_buffer_begin");
driver->command_buffer_begin(frames[frame].command_buffer); driver->command_buffer_begin(frames[frame].command_buffer);
// Reset the graph. // Reset the graph.
GodotProfileZoneGrouped(_profile_zone, "draw_graph.begin");
draw_graph.begin(); draw_graph.begin();
// Erase pending resources. // Erase pending resources.
GodotProfileZoneGrouped(_profile_zone, "_free_pending_resources");
_free_pending_resources(frame); _free_pending_resources(frame);
// Advance staging buffers if used. // Advance staging buffers if used.
@@ -6446,11 +6458,16 @@ void RenderingDevice::_end_frame() {
// The command buffer must be copied into a stack variable as the driver workarounds can change the command buffer in use. // The command buffer must be copied into a stack variable as the driver workarounds can change the command buffer in use.
RDD::CommandBufferID command_buffer = frames[frame].command_buffer; RDD::CommandBufferID command_buffer = frames[frame].command_buffer;
GodotProfileZoneGroupedFirst(_profile_zone, "_submit_transfer_workers");
_submit_transfer_workers(command_buffer); _submit_transfer_workers(command_buffer);
GodotProfileZoneGrouped(_profile_zone, "_submit_transfer_barriers");
_submit_transfer_barriers(command_buffer); _submit_transfer_barriers(command_buffer);
GodotProfileZoneGrouped(_profile_zone, "draw_graph.end");
draw_graph.end(RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS, command_buffer, frames[frame].command_buffer_pool); draw_graph.end(RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS, command_buffer, frames[frame].command_buffer_pool);
GodotProfileZoneGrouped(_profile_zone, "driver->command_buffer_end");
driver->command_buffer_end(command_buffer); driver->command_buffer_end(command_buffer);
GodotProfileZoneGrouped(_profile_zone, "driver->end_segment");
driver->end_segment(); driver->end_segment();
} }
@@ -6542,11 +6559,13 @@ void RenderingDevice::_stall_for_frame(uint32_t p_frame) {
thread_local PackedByteArray packed_byte_array; thread_local PackedByteArray packed_byte_array;
if (frames[p_frame].fence_signaled) { if (frames[p_frame].fence_signaled) {
GodotProfileZoneGroupedFirst(_profile_zone, "driver->fence_wait");
driver->fence_wait(frames[p_frame].fence); driver->fence_wait(frames[p_frame].fence);
frames[p_frame].fence_signaled = false; frames[p_frame].fence_signaled = false;
// Flush any pending requests for asynchronous buffer downloads. // Flush any pending requests for asynchronous buffer downloads.
if (!frames[p_frame].download_buffer_get_data_requests.is_empty()) { if (!frames[p_frame].download_buffer_get_data_requests.is_empty()) {
GodotProfileZoneGrouped(_profile_zone, "flush asynchronous buffer downloads");
for (uint32_t i = 0; i < frames[p_frame].download_buffer_get_data_requests.size(); i++) { for (uint32_t i = 0; i < frames[p_frame].download_buffer_get_data_requests.size(); i++) {
const BufferGetDataRequest &request = frames[p_frame].download_buffer_get_data_requests[i]; const BufferGetDataRequest &request = frames[p_frame].download_buffer_get_data_requests[i];
packed_byte_array.resize(request.size); packed_byte_array.resize(request.size);
@@ -6571,6 +6590,7 @@ void RenderingDevice::_stall_for_frame(uint32_t p_frame) {
// Flush any pending requests for asynchronous texture downloads. // Flush any pending requests for asynchronous texture downloads.
if (!frames[p_frame].download_texture_get_data_requests.is_empty()) { if (!frames[p_frame].download_texture_get_data_requests.is_empty()) {
GodotProfileZoneGrouped(_profile_zone, "flush asynchronous texture downloads");
uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP); uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);
for (uint32_t i = 0; i < frames[p_frame].download_texture_get_data_requests.size(); i++) { for (uint32_t i = 0; i < frames[p_frame].download_texture_get_data_requests.size(); i++) {
const TextureGetDataRequest &request = frames[p_frame].download_texture_get_data_requests[i]; const TextureGetDataRequest &request = frames[p_frame].download_texture_get_data_requests[i];
@@ -6618,6 +6638,7 @@ void RenderingDevice::_stall_for_frame(uint32_t p_frame) {
request.callback.call(packed_byte_array); request.callback.call(packed_byte_array);
} }
GodotProfileZoneGrouped(_profile_zone, "clear buffers");
frames[p_frame].download_texture_staging_buffers.clear(); frames[p_frame].download_texture_staging_buffers.clear();
frames[p_frame].download_buffer_texture_copy_regions.clear(); frames[p_frame].download_buffer_texture_copy_regions.clear();
frames[p_frame].download_texture_mipmap_offsets.clear(); frames[p_frame].download_texture_mipmap_offsets.clear();

View File

@@ -31,6 +31,7 @@
#include "rendering_server_default.h" #include "rendering_server_default.h"
#include "core/os/os.h" #include "core/os/os.h"
#include "core/profiling/profiling.h"
#include "renderer_canvas_cull.h" #include "renderer_canvas_cull.h"
#include "renderer_scene_cull.h" #include "renderer_scene_cull.h"
#include "rendering_server_globals.h" #include "rendering_server_globals.h"
@@ -66,6 +67,7 @@ void RenderingServerDefault::request_frame_drawn_callback(const Callable &p_call
} }
void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
GodotProfileZoneGroupedFirst(_profile_zone, "rasterizer->begin_frame");
RSG::rasterizer->begin_frame(frame_step); RSG::rasterizer->begin_frame(frame_step);
TIMESTAMP_BEGIN() TIMESTAMP_BEGIN()
@@ -75,6 +77,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RENDER_TIMESTAMP("Prepare Render Frame"); RENDER_TIMESTAMP("Prepare Render Frame");
#ifndef XR_DISABLED #ifndef XR_DISABLED
GodotProfileZoneGrouped(_profile_zone, "xr_server->pre_render");
XRServer *xr_server = XRServer::get_singleton(); XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) { if (xr_server != nullptr) {
// Let XR server know we're about to render a frame. // Let XR server know we're about to render a frame.
@@ -82,30 +85,41 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
} }
#endif // XR_DISABLED #endif // XR_DISABLED
GodotProfileZoneGrouped(_profile_zone, "scene->update");
RSG::scene->update(); //update scenes stuff before updating instances RSG::scene->update(); //update scenes stuff before updating instances
GodotProfileZoneGrouped(_profile_zone, "canvas->update");
RSG::canvas->update(); RSG::canvas->update();
frame_setup_time = double(OS::get_singleton()->get_ticks_usec() - time_usec) / 1000.0; frame_setup_time = double(OS::get_singleton()->get_ticks_usec() - time_usec) / 1000.0;
GodotProfileZoneGrouped(_profile_zone, "particles_storage->update_particles");
RSG::particles_storage->update_particles(); //need to be done after instances are updated (colliders and particle transforms), and colliders are rendered RSG::particles_storage->update_particles(); //need to be done after instances are updated (colliders and particle transforms), and colliders are rendered
GodotProfileZoneGrouped(_profile_zone, "scene->render_probes");
RSG::scene->render_probes(); RSG::scene->render_probes();
GodotProfileZoneGrouped(_profile_zone, "viewport->draw_viewports");
RSG::viewport->draw_viewports(p_swap_buffers); RSG::viewport->draw_viewports(p_swap_buffers);
GodotProfileZoneGrouped(_profile_zone, "canvas_render->update");
RSG::canvas_render->update(); RSG::canvas_render->update();
GodotProfileZoneGrouped(_profile_zone, "rasterizer->end_frame");
RSG::rasterizer->end_frame(p_swap_buffers); RSG::rasterizer->end_frame(p_swap_buffers);
#ifndef XR_DISABLED #ifndef XR_DISABLED
if (xr_server != nullptr) { if (xr_server != nullptr) {
GodotProfileZone("xr_server->end_frame");
// let our XR server know we're done so we can get our frame timing // let our XR server know we're done so we can get our frame timing
xr_server->end_frame(); xr_server->end_frame();
} }
#endif // XR_DISABLED #endif // XR_DISABLED
GodotProfileZoneGrouped(_profile_zone, "update_visibility_notifiers");
RSG::canvas->update_visibility_notifiers(); RSG::canvas->update_visibility_notifiers();
RSG::scene->update_visibility_notifiers(); RSG::scene->update_visibility_notifiers();
GodotProfileZoneGrouped(_profile_zone, "post_draw_steps");
if (create_thread) { if (create_thread) {
callable_mp(this, &RenderingServerDefault::_run_post_draw_steps).call_deferred(); callable_mp(this, &RenderingServerDefault::_run_post_draw_steps).call_deferred();
} else { } else {
@@ -113,6 +127,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
} }
if (RSG::utilities->get_captured_timestamps_count()) { if (RSG::utilities->get_captured_timestamps_count()) {
GodotProfileZoneGrouped(_profile_zone, "frame_profile");
Vector<FrameProfileArea> new_profile; Vector<FrameProfileArea> new_profile;
if (RSG::utilities->capturing_timestamps) { if (RSG::utilities->capturing_timestamps) {
new_profile.resize(RSG::utilities->get_captured_timestamps_count()); new_profile.resize(RSG::utilities->get_captured_timestamps_count());
@@ -143,6 +158,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
frame_profile_frame = RSG::utilities->get_captured_timestamps_frame(); frame_profile_frame = RSG::utilities->get_captured_timestamps_frame();
if (print_gpu_profile) { if (print_gpu_profile) {
GodotProfileZoneGrouped(_profile_zone, "gpu_profile");
if (print_frame_profile_ticks_from == 0) { if (print_frame_profile_ticks_from == 0) {
print_frame_profile_ticks_from = OS::get_singleton()->get_ticks_usec(); print_frame_profile_ticks_from = OS::get_singleton()->get_ticks_usec();
} }
@@ -185,6 +201,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
} }
} }
GodotProfileZoneGrouped(_profile_zone, "memory_info");
RSG::utilities->update_memory_info(); RSG::utilities->update_memory_info();
} }