From 65686dedf9778e829287f63c7179a523d44fa085 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 4 Apr 2024 10:18:08 +0200 Subject: [PATCH] Use WorkerThreadPool for Server threads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Servers now use WorkerThreadPool for background computation. * This helps keep the number of threads used fixed at all times. * It also ensures everything works on HTML5 with threads. * And makes it easier to support disabling threads for also HTML5. CommandQueueMT now syncs with the servers via the WorkerThreadPool yielding mechanism, which makes its classic main sync semaphore superfluous. Also, some warnings about calls that kill performance when using threaded rendering are removed because there's a mechanism that warns about that in a more general fashion. Co-authored-by: Pedro J. Estébanez --- core/config/engine.cpp | 16 +++++ core/config/engine.h | 7 +++ core/templates/command_queue_mt.cpp | 8 +-- core/templates/command_queue_mt.h | 43 +++++++------ drivers/gles3/storage/particles_storage.cpp | 6 -- main/main.cpp | 11 +++- servers/physics_server_2d_wrap_mt.cpp | 54 ++++++---------- servers/physics_server_2d_wrap_mt.h | 38 ++++++------ servers/physics_server_3d_wrap_mt.cpp | 48 +++++--------- servers/physics_server_3d_wrap_mt.h | 38 ++++++------ .../storage_rd/particles_storage.cpp | 6 -- .../rendering/rendering_server_default.cpp | 62 ++++++------------- servers/rendering/rendering_server_default.h | 21 ++++--- servers/rendering_server.cpp | 9 --- servers/server_wrap_mt_common.h | 45 ++++++++++++++ 15 files changed, 208 insertions(+), 204 deletions(-) diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 9f4bff37796..f2f8aebe8b5 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -82,6 +82,17 @@ int Engine::get_audio_output_latency() const { return _audio_output_latency; } +void Engine::increment_frames_drawn() { + if (frame_server_synced) { + server_syncs++; + } else { + server_syncs = 0; + } + frame_server_synced = false; + + frames_drawn++; +} + uint64_t Engine::get_frames_drawn() { return frames_drawn; } @@ -364,6 +375,11 @@ Engine *Engine::get_singleton() { return singleton; } +bool Engine::notify_frame_server_synced() { + frame_server_synced = true; + return server_syncs > SERVER_SYNC_FRAME_COUNT_WARNING; +} + Engine::Engine() { singleton = this; } diff --git a/core/config/engine.h b/core/config/engine.h index d1495b36c2d..8dece803e33 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -91,6 +91,10 @@ private: String write_movie_path; String shader_cache_path; + static constexpr int SERVER_SYNC_FRAME_COUNT_WARNING = 5; + int server_syncs = 0; + bool frame_server_synced = false; + public: static Engine *get_singleton(); @@ -179,6 +183,9 @@ public: bool is_generate_spirv_debug_info_enabled() const; int32_t get_gpu_index() const; + void increment_frames_drawn(); + bool notify_frame_server_synced(); + Engine(); virtual ~Engine() {} }; diff --git a/core/templates/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp index 6ecd75ebc15..0c5c6394a1a 100644 --- a/core/templates/command_queue_mt.cpp +++ b/core/templates/command_queue_mt.cpp @@ -70,14 +70,8 @@ CommandQueueMT::SyncSemaphore *CommandQueueMT::_alloc_sync_sem() { return &sync_sems[idx]; } -CommandQueueMT::CommandQueueMT(bool p_sync) { - if (p_sync) { - sync = memnew(Semaphore); - } +CommandQueueMT::CommandQueueMT() { } CommandQueueMT::~CommandQueueMT() { - if (sync) { - memdelete(sync); - } } diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h index 40561198517..c0740e93527 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -248,16 +248,17 @@ #define CMD_TYPE(N) Command##N #define CMD_ASSIGN_PARAM(N) cmd->p##N = p##N -#define DECL_PUSH(N) \ - template \ - void push(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \ - CMD_TYPE(N) *cmd = allocate_and_lock(); \ - cmd->instance = p_instance; \ - cmd->method = p_method; \ - SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ - unlock(); \ - if (sync) \ - sync->post(); \ +#define DECL_PUSH(N) \ + template \ + void push(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \ + CMD_TYPE(N) *cmd = allocate_and_lock(); \ + cmd->instance = p_instance; \ + cmd->method = p_method; \ + SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ + if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \ + WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \ + } \ + unlock(); \ } #define CMD_RET_TYPE(N) CommandRet##N @@ -272,9 +273,10 @@ SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ cmd->ret = r_ret; \ cmd->sync_sem = ss; \ + if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \ + WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \ + } \ unlock(); \ - if (sync) \ - sync->post(); \ ss->sem.wait(); \ ss->in_use = false; \ } @@ -290,9 +292,10 @@ cmd->method = p_method; \ SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ cmd->sync_sem = ss; \ + if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \ + WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \ + } \ unlock(); \ - if (sync) \ - sync->post(); \ ss->sem.wait(); \ ss->in_use = false; \ } @@ -340,7 +343,7 @@ class CommandQueueMT { LocalVector command_mem; SyncSemaphore sync_sems[SYNC_SEMAPHORES]; Mutex mutex; - Semaphore *sync = nullptr; + WorkerThreadPool::TaskID pump_task_id = WorkerThreadPool::INVALID_TASK_ID; uint64_t flush_read_ptr = 0; template @@ -421,12 +424,16 @@ public: } void wait_and_flush() { - ERR_FAIL_NULL(sync); - sync->wait(); + ERR_FAIL_COND(pump_task_id == WorkerThreadPool::INVALID_TASK_ID); + WorkerThreadPool::get_singleton()->wait_for_task_completion(pump_task_id); _flush(); } - CommandQueueMT(bool p_sync); + void set_pump_task_id(WorkerThreadPool::TaskID p_task_id) { + pump_task_id = p_task_id; + } + + CommandQueueMT(); ~CommandQueueMT(); }; diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp index 09878aaee40..fee90599e05 100644 --- a/drivers/gles3/storage/particles_storage.cpp +++ b/drivers/gles3/storage/particles_storage.cpp @@ -135,7 +135,6 @@ bool ParticlesStorage::particles_get_emitting(RID p_particles) { return false; } - ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, false); @@ -380,10 +379,6 @@ void ParticlesStorage::particles_request_process(RID p_particles) { } AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) { - if (RSG::threaded) { - WARN_PRINT_ONCE("Calling this function with threaded rendering enabled stalls the renderer, use with care."); - } - const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, AABB()); @@ -1207,7 +1202,6 @@ Dependency *ParticlesStorage::particles_get_dependency(RID p_particles) const { } bool ParticlesStorage::particles_is_inactive(RID p_particles) const { - ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, false); return !particles->emitting && particles->inactive; diff --git a/main/main.cpp b/main/main.cpp index 357033b6d8b..5f5118aa75c 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2274,6 +2274,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph // Editor and project manager cannot run with rendering in a separate thread (they will crash on startup). rtm = OS::RENDER_THREAD_SAFE; } +#if !defined(THREADS_ENABLED) + rtm = OS::RENDER_THREAD_SAFE; +#endif OS::get_singleton()->_render_thread_mode = OS::RenderThreadMode(rtm); } @@ -2717,7 +2720,9 @@ Error Main::setup2() { } if (OS::get_singleton()->_render_thread_mode == OS::RENDER_SEPARATE_THREAD) { - WARN_PRINT("The Multi-Threaded rendering thread model is experimental, and has known issues which can lead to project crashes. Use the Single-Safe option in the project settings instead."); + WARN_PRINT("The Multi-Threaded rendering thread model is experimental. Feel free to try it since it will eventually become a stable feature.\n" + "However, bear in mind that at the moment it can lead to project crashes or instability.\n" + "So, unless you want to test the engine, use the Single-Safe option in the project settings instead."); } /* Initialize Pen Tablet Driver */ @@ -4025,11 +4030,11 @@ bool Main::iteration() { if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) { if (RenderingServer::get_singleton()->has_changed()) { RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands - Engine::get_singleton()->frames_drawn++; + Engine::get_singleton()->increment_frames_drawn(); } } else { RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands - Engine::get_singleton()->frames_drawn++; + Engine::get_singleton()->increment_frames_drawn(); force_redraw_requested = false; } } diff --git a/servers/physics_server_2d_wrap_mt.cpp b/servers/physics_server_2d_wrap_mt.cpp index f0d31ddb7ab..4548bb91cbd 100644 --- a/servers/physics_server_2d_wrap_mt.cpp +++ b/servers/physics_server_2d_wrap_mt.cpp @@ -33,7 +33,7 @@ #include "core/os/os.h" void PhysicsServer2DWrapMT::thread_exit() { - exit.set(); + exit = true; } void PhysicsServer2DWrapMT::thread_step(real_t p_delta) { @@ -41,25 +41,18 @@ void PhysicsServer2DWrapMT::thread_step(real_t p_delta) { step_sem.post(); } -void PhysicsServer2DWrapMT::_thread_callback(void *_instance) { - PhysicsServer2DWrapMT *vsmt = reinterpret_cast(_instance); - - vsmt->thread_loop(); -} - void PhysicsServer2DWrapMT::thread_loop() { server_thread = Thread::get_caller_id(); physics_server_2d->init(); - exit.clear(); - step_thread_up.set(); - while (!exit.is_set()) { - // flush commands one by one, until exit is requested - command_queue.wait_and_flush(); + command_queue.set_pump_task_id(server_task_id); + while (!exit) { + WorkerThreadPool::get_singleton()->yield(); + command_queue.flush_all(); } - command_queue.flush_all(); // flush all + command_queue.flush_all(); physics_server_2d->finish(); } @@ -70,18 +63,14 @@ void PhysicsServer2DWrapMT::step(real_t p_step) { if (create_thread) { command_queue.push(this, &PhysicsServer2DWrapMT::thread_step, p_step); } else { - command_queue.flush_all(); //flush all pending from other threads + command_queue.flush_all(); // Flush all pending from other threads. physics_server_2d->step(p_step); } } void PhysicsServer2DWrapMT::sync() { if (create_thread) { - if (first_frame) { - first_frame = false; - } else { - step_sem.wait(); //must not wait if a step was not issued - } + step_sem.wait(); } physics_server_2d->sync(); } @@ -96,39 +85,34 @@ void PhysicsServer2DWrapMT::end_sync() { void PhysicsServer2DWrapMT::init() { if (create_thread) { - thread.start(_thread_callback, this); - while (!step_thread_up.is_set()) { - OS::get_singleton()->delay_usec(1000); - } + exit = false; + server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer2DWrapMT::thread_loop), true); + step_sem.post(); } else { physics_server_2d->init(); } } void PhysicsServer2DWrapMT::finish() { - if (thread.is_started()) { + if (create_thread) { command_queue.push(this, &PhysicsServer2DWrapMT::thread_exit); - thread.wait_to_finish(); + if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id); + server_task_id = WorkerThreadPool::INVALID_TASK_ID; + } } else { physics_server_2d->finish(); } } -PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) : - command_queue(p_create_thread) { +PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) { physics_server_2d = p_contained; create_thread = p_create_thread; - - if (!p_create_thread) { - server_thread = Thread::get_caller_id(); - } else { - server_thread = 0; + if (!create_thread) { + server_thread = Thread::MAIN_ID; } - - main_thread = Thread::get_caller_id(); } PhysicsServer2DWrapMT::~PhysicsServer2DWrapMT() { memdelete(physics_server_2d); - //finish(); } diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h index 3bebe5df851..5e2b3b40866 100644 --- a/servers/physics_server_2d_wrap_mt.h +++ b/servers/physics_server_2d_wrap_mt.h @@ -32,6 +32,7 @@ #define PHYSICS_SERVER_2D_WRAP_MT_H #include "core/config/project_settings.h" +#include "core/object/worker_thread_pool.h" #include "core/os/thread.h" #include "core/templates/command_queue_mt.h" #include "core/templates/safe_refcount.h" @@ -43,30 +44,27 @@ #define SYNC_DEBUG #endif +#ifdef DEBUG_ENABLED +#define MAIN_THREAD_SYNC_WARN WARN_PRINT("Call to " + String(__FUNCTION__) + " causing PhysicsServer2D synchronizations on every frame. This significantly affects performance."); +#endif + class PhysicsServer2DWrapMT : public PhysicsServer2D { - mutable PhysicsServer2D *physics_server_2d; + mutable PhysicsServer2D *physics_server_2d = nullptr; mutable CommandQueueMT command_queue; - static void _thread_callback(void *_instance); void thread_loop(); - Thread::ID server_thread; - Thread::ID main_thread; - SafeFlag exit; - Thread thread; - SafeFlag step_thread_up; + Thread::ID server_thread = Thread::UNASSIGNED_ID; + WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID; + bool exit = false; + Semaphore step_sem; bool create_thread = false; - Semaphore step_sem; void thread_step(real_t p_delta); void thread_exit(); - bool first_frame = true; - - Mutex alloc_mutex; - public: #define ServerName PhysicsServer2D #define ServerNameWrapMT PhysicsServer2DWrapMT @@ -94,7 +92,7 @@ public: //these work well, but should be used from the main thread only bool shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + ERR_FAIL_COND_V(!Thread::is_main_thread(), false); return physics_server_2d->shape_collide(p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, r_result_count); } @@ -109,18 +107,18 @@ public: // this function only works on physics process, errors and returns null otherwise PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + ERR_FAIL_COND_V(!Thread::is_main_thread(), nullptr); return physics_server_2d->space_get_direct_state(p_space); } FUNC2(space_set_debug_contacts, RID, int); virtual Vector space_get_contacts(RID p_space) const override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), Vector()); + ERR_FAIL_COND_V(!Thread::is_main_thread(), Vector()); return physics_server_2d->space_get_contacts(p_space); } virtual int space_get_contact_count(RID p_space) const override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0); + ERR_FAIL_COND_V(!Thread::is_main_thread(), 0); return physics_server_2d->space_get_contact_count(p_space); } @@ -261,13 +259,13 @@ public: FUNC2(body_set_pickable, RID, bool); bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + ERR_FAIL_COND_V(!Thread::is_main_thread(), false); return physics_server_2d->body_test_motion(p_body, p_parameters, r_result); } // this function only works on physics process, errors and returns null otherwise PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + ERR_FAIL_COND_V(!Thread::is_main_thread(), nullptr); return physics_server_2d->body_get_direct_state(p_body); } @@ -338,4 +336,8 @@ public: #endif #undef SYNC_DEBUG +#ifdef DEBUG_ENABLED +#undef MAIN_THREAD_SYNC_WARN +#endif + #endif // PHYSICS_SERVER_2D_WRAP_MT_H diff --git a/servers/physics_server_3d_wrap_mt.cpp b/servers/physics_server_3d_wrap_mt.cpp index 9cdd1445257..f8f60281a78 100644 --- a/servers/physics_server_3d_wrap_mt.cpp +++ b/servers/physics_server_3d_wrap_mt.cpp @@ -41,22 +41,15 @@ void PhysicsServer3DWrapMT::thread_step(real_t p_delta) { step_sem.post(); } -void PhysicsServer3DWrapMT::_thread_callback(void *_instance) { - PhysicsServer3DWrapMT *vsmt = reinterpret_cast(_instance); - - vsmt->thread_loop(); -} - void PhysicsServer3DWrapMT::thread_loop() { server_thread = Thread::get_caller_id(); physics_server_3d->init(); - exit = false; - step_thread_up = true; + command_queue.set_pump_task_id(server_task_id); while (!exit) { - // flush commands one by one, until exit is requested - command_queue.wait_and_flush(); + WorkerThreadPool::get_singleton()->yield(); + command_queue.flush_all(); } command_queue.flush_all(); // flush all @@ -70,18 +63,14 @@ void PhysicsServer3DWrapMT::step(real_t p_step) { if (create_thread) { command_queue.push(this, &PhysicsServer3DWrapMT::thread_step, p_step); } else { - command_queue.flush_all(); //flush all pending from other threads + command_queue.flush_all(); // Flush all pending from other threads. physics_server_3d->step(p_step); } } void PhysicsServer3DWrapMT::sync() { if (create_thread) { - if (first_frame) { - first_frame = false; - } else { - step_sem.wait(); //must not wait if a step was not issued - } + step_sem.wait(); } physics_server_3d->sync(); } @@ -96,39 +85,34 @@ void PhysicsServer3DWrapMT::end_sync() { void PhysicsServer3DWrapMT::init() { if (create_thread) { - thread.start(_thread_callback, this); - while (!step_thread_up) { - OS::get_singleton()->delay_usec(1000); - } + exit = false; + server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer3DWrapMT::thread_loop), true); + step_sem.post(); } else { physics_server_3d->init(); } } void PhysicsServer3DWrapMT::finish() { - if (thread.is_started()) { + if (create_thread) { command_queue.push(this, &PhysicsServer3DWrapMT::thread_exit); - thread.wait_to_finish(); + if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id); + server_task_id = WorkerThreadPool::INVALID_TASK_ID; + } } else { physics_server_3d->finish(); } } -PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread) : - command_queue(p_create_thread) { +PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread) { physics_server_3d = p_contained; create_thread = p_create_thread; - - if (!p_create_thread) { - server_thread = Thread::get_caller_id(); - } else { - server_thread = 0; + if (!create_thread) { + server_thread = Thread::MAIN_ID; } - - main_thread = Thread::get_caller_id(); } PhysicsServer3DWrapMT::~PhysicsServer3DWrapMT() { memdelete(physics_server_3d); - //finish(); } diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h index fc8930977d1..22f3ee0e455 100644 --- a/servers/physics_server_3d_wrap_mt.h +++ b/servers/physics_server_3d_wrap_mt.h @@ -32,6 +32,7 @@ #define PHYSICS_SERVER_3D_WRAP_MT_H #include "core/config/project_settings.h" +#include "core/object/worker_thread_pool.h" #include "core/os/thread.h" #include "core/templates/command_queue_mt.h" #include "servers/physics_server_3d.h" @@ -42,30 +43,27 @@ #define SYNC_DEBUG #endif +#ifdef DEBUG_ENABLED +#define MAIN_THREAD_SYNC_WARN WARN_PRINT("Call to " + String(__FUNCTION__) + " causing PhysicsServer3D synchronizations on every frame. This significantly affects performance."); +#endif + class PhysicsServer3DWrapMT : public PhysicsServer3D { - mutable PhysicsServer3D *physics_server_3d; + mutable PhysicsServer3D *physics_server_3d = nullptr; mutable CommandQueueMT command_queue; - static void _thread_callback(void *_instance); void thread_loop(); - Thread::ID server_thread; - Thread::ID main_thread; - volatile bool exit = false; - Thread thread; - volatile bool step_thread_up = false; + Thread::ID server_thread = Thread::UNASSIGNED_ID; + WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID; + bool exit = false; + Semaphore step_sem; bool create_thread = false; - Semaphore step_sem; void thread_step(real_t p_delta); void thread_exit(); - bool first_frame = true; - - Mutex alloc_mutex; - public: #define ServerName PhysicsServer3D #define ServerNameWrapMT PhysicsServer3DWrapMT @@ -98,7 +96,7 @@ public: #if 0 //these work well, but should be used from the main thread only bool shape_collide(RID p_shape_A, const Transform &p_xform_A, const Vector3 &p_motion_A, RID p_shape_B, const Transform &p_xform_B, const Vector3 &p_motion_B, Vector3 *r_results, int p_result_max, int &r_result_count) { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + ERR_FAIL_COND_V(!Thread::is_main_thread(), false); return physics_server_3d->shape_collide(p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, r_result_count); } #endif @@ -113,18 +111,18 @@ public: // this function only works on physics process, errors and returns null otherwise PhysicsDirectSpaceState3D *space_get_direct_state(RID p_space) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + ERR_FAIL_COND_V(!Thread::is_main_thread(), nullptr); return physics_server_3d->space_get_direct_state(p_space); } FUNC2(space_set_debug_contacts, RID, int); virtual Vector space_get_contacts(RID p_space) const override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), Vector()); + ERR_FAIL_COND_V(!Thread::is_main_thread(), Vector()); return physics_server_3d->space_get_contacts(p_space); } virtual int space_get_contact_count(RID p_space) const override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0); + ERR_FAIL_COND_V(!Thread::is_main_thread(), 0); return physics_server_3d->space_get_contact_count(p_space); } @@ -260,13 +258,13 @@ public: FUNC2(body_set_ray_pickable, RID, bool); bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + ERR_FAIL_COND_V(!Thread::is_main_thread(), false); return physics_server_3d->body_test_motion(p_body, p_parameters, r_result); } // this function only works on physics process, errors and returns null otherwise PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + ERR_FAIL_COND_V(!Thread::is_main_thread(), nullptr); return physics_server_3d->body_get_direct_state(p_body); } @@ -411,4 +409,8 @@ public: #endif #undef SYNC_DEBUG +#ifdef DEBUG_ENABLED +#undef MAIN_THREAD_SYNC_WARN +#endif + #endif // PHYSICS_SERVER_3D_WRAP_MT_H diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index c9c7c53d046..f7b28e7a1ec 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -257,7 +257,6 @@ void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) } bool ParticlesStorage::particles_get_emitting(RID p_particles) { - ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, false); @@ -608,10 +607,6 @@ void ParticlesStorage::particles_request_process(RID p_particles) { } AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) { - if (RSG::threaded) { - WARN_PRINT_ONCE("Calling this function with threaded rendering enabled stalls the renderer, use with care."); - } - const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, AABB()); @@ -1642,7 +1637,6 @@ Dependency *ParticlesStorage::particles_get_dependency(RID p_particles) const { } bool ParticlesStorage::particles_is_inactive(RID p_particles) const { - ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, false); return !particles->emitting && particles->inactive; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 268b49ae807..7e5ccee0e39 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -69,9 +69,6 @@ void RenderingServerDefault::request_frame_drawn_callback(const Callable &p_call } void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { - //needs to be done before changes is reset to 0, to not force the editor to redraw - RS::get_singleton()->emit_signal(SNAME("frame_pre_draw")); - changes = 0; RSG::rasterizer->begin_frame(frame_step); @@ -220,16 +217,9 @@ void RenderingServerDefault::_finish() { void RenderingServerDefault::init() { if (create_thread) { - print_verbose("RenderingServerWrapMT: Creating render thread"); + print_verbose("RenderingServerWrapMT: Starting render thread"); DisplayServer::get_singleton()->release_rendering_thread(); - if (create_thread) { - thread.start(_thread_callback, this); - print_verbose("RenderingServerWrapMT: Starting render thread"); - } - while (!draw_thread_up.is_set()) { - OS::get_singleton()->delay_usec(1000); - } - print_verbose("RenderingServerWrapMT: Finished render thread"); + server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &RenderingServerDefault::_thread_loop), true); } else { _init(); } @@ -238,8 +228,9 @@ void RenderingServerDefault::init() { void RenderingServerDefault::finish() { if (create_thread) { command_queue.push(this, &RenderingServerDefault::_thread_exit); - if (thread.is_started()) { - thread.wait_to_finish(); + if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id); + server_task_id = WorkerThreadPool::INVALID_TASK_ID; } } else { _finish(); @@ -337,37 +328,29 @@ Size2i RenderingServerDefault::get_maximum_viewport_size() const { } void RenderingServerDefault::_thread_exit() { - exit.set(); + exit = true; } void RenderingServerDefault::_thread_draw(bool p_swap_buffers, double frame_step) { _draw(p_swap_buffers, frame_step); } -void RenderingServerDefault::_thread_flush() { -} - -void RenderingServerDefault::_thread_callback(void *_instance) { - RenderingServerDefault *vsmt = reinterpret_cast(_instance); - - vsmt->_thread_loop(); -} - void RenderingServerDefault::_thread_loop() { server_thread = Thread::get_caller_id(); DisplayServer::get_singleton()->gl_window_make_current(DisplayServer::MAIN_WINDOW_ID); // Move GL to this thread. _init(); - draw_thread_up.set(); - while (!exit.is_set()) { - // flush commands one by one, until exit is requested - command_queue.wait_and_flush(); + command_queue.set_pump_task_id(server_task_id); + while (!exit) { + WorkerThreadPool::get_singleton()->yield(); + command_queue.flush_all(); } - command_queue.flush_all(); // flush all + command_queue.flush_all(); _finish(); + DisplayServer::get_singleton()->release_rendering_thread(); } /* INTERPOLATION */ @@ -383,15 +366,15 @@ void RenderingServerDefault::set_physics_interpolation_enabled(bool p_enabled) { /* EVENT QUEUING */ void RenderingServerDefault::sync() { - if (create_thread) { - command_queue.push_and_sync(this, &RenderingServerDefault::_thread_flush); - } else { - command_queue.flush_all(); //flush all pending from other threads + if (!create_thread) { + command_queue.flush_all(); // Flush all pending from other threads. } } void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) { ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Manually triggering the draw function from the RenderingServer can only be done on the main thread. Call this function from the main thread or use call_deferred()."); + // Needs to be done before changes is reset to 0, to not force the editor to redraw. + RS::get_singleton()->emit_signal(SNAME("frame_pre_draw")); if (create_thread) { command_queue.push(this, &RenderingServerDefault::_thread_draw, p_swap_buffers, frame_step); } else { @@ -403,21 +386,14 @@ void RenderingServerDefault::_call_on_render_thread(const Callable &p_callable) p_callable.call(); } -RenderingServerDefault::RenderingServerDefault(bool p_create_thread) : - command_queue(p_create_thread) { +RenderingServerDefault::RenderingServerDefault(bool p_create_thread) { RenderingServer::init(); -#ifdef THREADS_ENABLED create_thread = p_create_thread; if (!create_thread) { - server_thread = Thread::get_caller_id(); - } else { - server_thread = 0; + server_thread = Thread::MAIN_ID; } -#else - create_thread = false; - server_thread = Thread::get_main_id(); -#endif + RSG::threaded = create_thread; RSG::canvas = memnew(RendererCanvasCull); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index c50472c0cd7..f94323f198e 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -31,6 +31,7 @@ #ifndef RENDERING_SERVER_DEFAULT_H #define RENDERING_SERVER_DEFAULT_H +#include "core/object/worker_thread_pool.h" #include "core/os/thread.h" #include "core/templates/command_queue_mt.h" #include "core/templates/hash_map.h" @@ -75,22 +76,17 @@ class RenderingServerDefault : public RenderingServer { mutable CommandQueueMT command_queue; - static void _thread_callback(void *_instance); void _thread_loop(); - Thread::ID server_thread = 0; - SafeFlag exit; - Thread thread; - SafeFlag draw_thread_up; - bool create_thread; + Thread::ID server_thread = Thread::UNASSIGNED_ID; + WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID; + bool exit = false; + bool create_thread = false; void _thread_draw(bool p_swap_buffers, double frame_step); - void _thread_flush(); void _thread_exit(); - Mutex alloc_mutex; - void _draw(bool p_swap_buffers, double frame_step); void _init(); void _finish(); @@ -127,6 +123,10 @@ public: #define SYNC_DEBUG #endif +#ifdef DEBUG_ENABLED +#define MAIN_THREAD_SYNC_WARN WARN_PRINT("Call to " + String(__FUNCTION__) + " causing RenderingServer synchronizations on every frame. This significantly affects performance."); +#endif + #include "servers/server_wrap_mt_common.h" /* TEXTURE API */ @@ -1013,6 +1013,9 @@ public: #undef ServerName #undef WRITE_ACTION #undef SYNC_DEBUG +#ifdef DEBUG_ENABLED +#undef MAIN_THREAD_SYNC_WARN +#endif virtual uint64_t get_rendering_info(RenderingInfo p_info) override; virtual RenderingDevice::DeviceType get_video_adapter_type() const override; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 96d317ebd32..bbe6b1ad0da 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -83,25 +83,16 @@ static PackedInt64Array to_int_array(const Vector &ids) { } PackedInt64Array RenderingServer::_instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario) const { - if (RSG::threaded) { - WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); - } Vector ids = instances_cull_aabb(p_aabb, p_scenario); return to_int_array(ids); } PackedInt64Array RenderingServer::_instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { - if (RSG::threaded) { - WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); - } Vector ids = instances_cull_ray(p_from, p_to, p_scenario); return to_int_array(ids); } PackedInt64Array RenderingServer::_instances_cull_convex_bind(const TypedArray &p_convex, RID p_scenario) const { - if (RSG::threaded) { - WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); - } Vector planes; for (int i = 0; i < p_convex.size(); ++i) { const Variant &v = p_convex[i]; diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h index 1a73c97fc7d..40867490ca3 100644 --- a/servers/server_wrap_mt_common.h +++ b/servers/server_wrap_mt_common.h @@ -31,12 +31,22 @@ #ifndef SERVER_WRAP_MT_COMMON_H #define SERVER_WRAP_MT_COMMON_H +#ifdef DEBIG_ENABLED +#define MAIN_THREAD_SYNC_CHECK \ + if (unlikely(Thread::is_main_thread() && Engine::get_singleton()->notify_frame_server_synced())) { \ + MAIN_THREAD_SYNC_WARN \ + } +#else +#define MAIN_THREAD_SYNC_CHECK +#endif + #define FUNC0R(m_r, m_type) \ virtual m_r m_type() override { \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -68,6 +78,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -102,6 +113,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(); \ @@ -113,6 +125,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(); \ @@ -128,6 +141,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -141,6 +155,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -154,6 +169,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1); \ @@ -165,6 +181,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1); \ @@ -199,6 +216,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -212,6 +230,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -225,6 +244,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2); \ @@ -236,6 +256,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2); \ @@ -270,6 +291,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -283,6 +305,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -296,6 +319,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3); \ @@ -307,6 +331,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3); \ @@ -341,6 +366,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -354,6 +380,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -367,6 +394,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4); \ @@ -378,6 +406,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4); \ @@ -412,6 +441,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -425,6 +455,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -438,6 +469,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5); \ @@ -449,6 +481,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5); \ @@ -483,6 +516,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -496,6 +530,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -509,6 +544,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6); \ @@ -520,6 +556,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6); \ @@ -554,6 +591,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -567,6 +605,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -580,6 +619,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ @@ -591,6 +631,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ @@ -625,6 +666,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -638,6 +680,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -651,6 +694,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ @@ -662,6 +706,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \