Skip to content

Commit

Permalink
Use WorkerThreadPool for Server threads
Browse files Browse the repository at this point in the history
* 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.

The only downside of this is that GLES3 threads likely no longer work because every time the render thread is called, the thread context is different. This needs to be researched how to fix. Maybe if GLES3 is used, threaded rendering server should be disabled for the time being?
  • Loading branch information
reduz committed Jan 26, 2024
1 parent 0bcc0e9 commit 900dc33
Show file tree
Hide file tree
Showing 13 changed files with 598 additions and 533 deletions.
15 changes: 15 additions & 0 deletions core/config/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ 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 = 0;

frames_drawn++;
}
uint64_t Engine::get_frames_drawn() {
return frames_drawn;
}
Expand Down Expand Up @@ -351,6 +361,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;
}
Expand Down
7 changes: 7 additions & 0 deletions core/config/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ class Engine {
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();

Expand Down Expand Up @@ -175,6 +179,9 @@ class Engine {
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() {}
};
Expand Down
4 changes: 4 additions & 0 deletions drivers/gles3/rasterizer_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ void RasterizerGLES3::end_viewport(bool p_swap_buffers) {
}
}

void RasterizerGLES3::context_move_to_current_thread() {
// I need to move the OpenGL context thread to this thread
}

void RasterizerGLES3::clear_depth(float p_depth) {
#ifdef GL_API_ENABLED
if (is_gles_over_gl()) {
Expand Down
2 changes: 2 additions & 0 deletions drivers/gles3/rasterizer_gles3.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ class RasterizerGLES3 : public RendererCompositor {
_ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
_ALWAYS_INLINE_ double get_total_time() const { return time_total; }

virtual void context_move_to_current_thread();

static RasterizerGLES3 *get_singleton() { return singleton; }
RasterizerGLES3();
~RasterizerGLES3();
Expand Down
4 changes: 2 additions & 2 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3799,11 +3799,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;
}
}
Expand Down
67 changes: 21 additions & 46 deletions servers/physics_server_2d_wrap_mt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,43 +32,28 @@

#include "core/os/os.h"

void PhysicsServer2DWrapMT::thread_exit() {
exit.set();
}

void PhysicsServer2DWrapMT::thread_step(real_t p_delta) {
server_thread = Thread::get_caller_id();
command_queue.flush_all();
physics_server_2d->step(p_delta);
step_sem.post();
}

void PhysicsServer2DWrapMT::_thread_callback(void *_instance) {
PhysicsServer2DWrapMT *vsmt = reinterpret_cast<PhysicsServer2DWrapMT *>(_instance);

vsmt->thread_loop();
command_queue.flush_all(); // Flush pending commands before and after
server_thread = Thread::UNASSIGNED_ID;
}

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();
void PhysicsServer2DWrapMT::_main_thread_sync() {
if (task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(task_id);
task_id = WorkerThreadPool::INVALID_TASK_ID;
}

command_queue.flush_all(); // flush all

physics_server_2d->finish();
server_thread = Thread::MAIN_ID;
}

/* EVENT QUEUING */

void PhysicsServer2DWrapMT::step(real_t p_step) {
if (create_thread) {
command_queue.push(this, &PhysicsServer2DWrapMT::thread_step, p_step);
task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer2DWrapMT::thread_step).bind(p_step), true);
} else {
command_queue.flush_all(); //flush all pending from other threads
physics_server_2d->step(p_step);
Expand All @@ -77,10 +62,9 @@ void PhysicsServer2DWrapMT::step(real_t 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
if (task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(task_id);
task_id = WorkerThreadPool::INVALID_TASK_ID;
}
}
physics_server_2d->sync();
Expand All @@ -95,24 +79,15 @@ void PhysicsServer2DWrapMT::end_sync() {
}

void PhysicsServer2DWrapMT::init() {
if (create_thread) {
//OS::get_singleton()->release_rendering_thread();
thread.start(_thread_callback, this);
while (!step_thread_up.is_set()) {
OS::get_singleton()->delay_usec(1000);
}
} else {
physics_server_2d->init();
}
physics_server_2d->init();
}

void PhysicsServer2DWrapMT::finish() {
if (thread.is_started()) {
command_queue.push(this, &PhysicsServer2DWrapMT::thread_exit);
thread.wait_to_finish();
} else {
physics_server_2d->finish();
if (task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(task_id);
task_id = WorkerThreadPool::INVALID_TASK_ID;
}
physics_server_2d->finish();
}

PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) :
Expand All @@ -121,12 +96,12 @@ PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool
create_thread = p_create_thread;

if (!p_create_thread) {
server_thread = Thread::get_caller_id();
server_thread = Thread::MAIN_ID;
} else {
server_thread = 0;
server_thread = Thread::UNASSIGNED_ID;
}

main_thread = Thread::get_caller_id();
main_thread = Thread::MAIN_ID;
}

PhysicsServer2DWrapMT::~PhysicsServer2DWrapMT() {
Expand Down
21 changes: 16 additions & 5 deletions servers/physics_server_2d_wrap_mt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -43,29 +44,38 @@
#define SYNC_DEBUG
#endif

#ifdef DEBUG_ENABLED
#define MAIN_THREAD_SYNC \
if (Engine::get_singleton()->notify_frame_server_synced()) { \
WARN_PRINT("Call to " + String(__FUNCTION__) + " causing PhysicsServer2D synchronizations on every frame. This significantly affects performance."); \
} \
const_cast<PhysicsServer2DWrapMT *>(this)->_main_thread_sync();
#else
#define MAIN_THREAD_SYNC const_cast<PhysicsServer2DWrapMT *>(this)->_main_thread_sync();
#endif

class PhysicsServer2DWrapMT : public PhysicsServer2D {
mutable PhysicsServer2D *physics_server_2d;

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;
bool create_thread = false;
WorkerThreadPool::TaskID task_id = WorkerThreadPool::INVALID_TASK_ID;

Semaphore step_sem;
void thread_step(real_t p_delta);

void thread_exit();

void _main_thread_sync();

bool first_frame = true;

Mutex alloc_mutex;
int pool_max_size = 0;

public:
#define ServerName PhysicsServer2D
Expand Down Expand Up @@ -337,5 +347,6 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D {
#undef DEBUG_SYNC
#endif
#undef SYNC_DEBUG
#undef MAIN_THREAD_SYNC

#endif // PHYSICS_SERVER_2D_WRAP_MT_H
67 changes: 21 additions & 46 deletions servers/physics_server_3d_wrap_mt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,43 +32,28 @@

#include "core/os/os.h"

void PhysicsServer3DWrapMT::thread_exit() {
exit = true;
}

void PhysicsServer3DWrapMT::thread_step(real_t p_delta) {
server_thread = Thread::get_caller_id();
command_queue.flush_all();
physics_server_3d->step(p_delta);
step_sem.post();
}

void PhysicsServer3DWrapMT::_thread_callback(void *_instance) {
PhysicsServer3DWrapMT *vsmt = reinterpret_cast<PhysicsServer3DWrapMT *>(_instance);

vsmt->thread_loop();
command_queue.flush_all(); // Flush pending commands before and after
server_thread = Thread::UNASSIGNED_ID;
}

void PhysicsServer3DWrapMT::thread_loop() {
server_thread = Thread::get_caller_id();

physics_server_3d->init();

exit = false;
step_thread_up = true;
while (!exit) {
// flush commands one by one, until exit is requested
command_queue.wait_and_flush();
void PhysicsServer3DWrapMT::_main_thread_sync() {
if (task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(task_id);
task_id = WorkerThreadPool::INVALID_TASK_ID;
}

command_queue.flush_all(); // flush all

physics_server_3d->finish();
server_thread = Thread::MAIN_ID;
}

/* EVENT QUEUING */

void PhysicsServer3DWrapMT::step(real_t p_step) {
if (create_thread) {
command_queue.push(this, &PhysicsServer3DWrapMT::thread_step, p_step);
task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer3DWrapMT::thread_step).bind(p_step), true);
} else {
command_queue.flush_all(); //flush all pending from other threads
physics_server_3d->step(p_step);
Expand All @@ -77,10 +62,9 @@ void PhysicsServer3DWrapMT::step(real_t 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
if (task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(task_id);
task_id = WorkerThreadPool::INVALID_TASK_ID;
}
}
physics_server_3d->sync();
Expand All @@ -95,24 +79,15 @@ void PhysicsServer3DWrapMT::end_sync() {
}

void PhysicsServer3DWrapMT::init() {
if (create_thread) {
//OS::get_singleton()->release_rendering_thread();
thread.start(_thread_callback, this);
while (!step_thread_up) {
OS::get_singleton()->delay_usec(1000);
}
} else {
physics_server_3d->init();
}
physics_server_3d->init();
}

void PhysicsServer3DWrapMT::finish() {
if (thread.is_started()) {
command_queue.push(this, &PhysicsServer3DWrapMT::thread_exit);
thread.wait_to_finish();
} else {
physics_server_3d->finish();
if (task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(task_id);
task_id = WorkerThreadPool::INVALID_TASK_ID;
}
physics_server_3d->finish();
}

PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread) :
Expand All @@ -121,12 +96,12 @@ PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool
create_thread = p_create_thread;

if (!p_create_thread) {
server_thread = Thread::get_caller_id();
server_thread = Thread::MAIN_ID;
} else {
server_thread = 0;
server_thread = Thread::UNASSIGNED_ID;
}

main_thread = Thread::get_caller_id();
main_thread = Thread::MAIN_ID;
}

PhysicsServer3DWrapMT::~PhysicsServer3DWrapMT() {
Expand Down
Loading

0 comments on commit 900dc33

Please sign in to comment.