diff options
author | reduz <reduzio@gmail.com> | 2021-02-09 13:19:03 -0300 |
---|---|---|
committer | reduz <reduzio@gmail.com> | 2021-02-10 13:21:46 -0300 |
commit | 8b19ffd810a1471ab870b7229047ad2101341330 (patch) | |
tree | 19bf66787e48cebd86b494846d147db1f163f87c /core | |
parent | f3d15771bf33e68b26058806f9310ac074c56e5c (diff) |
Make Servers truly Thread Safe
-Rendering server now uses a split RID allocate/initialize internally, this allows generating RIDs immediately but initialization to happen later on the proper thread (as rendering APIs generally requiere to call on the right thread).
-RenderingServerWrapMT is no more, multithreading is done in RenderingServerDefault.
-Some functions like texture or mesh creation, when renderer supports it, can register and return immediately (so no waiting for server API to flush, and saving staging and command buffer memory).
-3D physics server changed to be made multithread friendly.
-Added PhysicsServer3DWrapMT to use 3D physics server from multiple threads.
-Disablet Bullet (too much effort to make multithread friendly, this needs to be fixed eventually).
Diffstat (limited to 'core')
-rw-r--r-- | core/config/project_settings.cpp | 4 | ||||
-rw-r--r-- | core/templates/command_queue_mt.h | 5 | ||||
-rw-r--r-- | core/templates/rid_owner.h | 91 |
3 files changed, 89 insertions, 11 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 9b28ef7b81..b4ca31d77a 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1244,8 +1244,8 @@ ProjectSettings::ProjectSettings() { custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor"); custom_prop_info["rendering/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded"); - custom_prop_info["physics/2d/thread_model"] = PropertyInfo(Variant::INT, "physics/2d/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded"); - custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects"); + GLOBAL_DEF("physics/2d/run_on_thread", false); + GLOBAL_DEF("physics/3d/run_on_thread", false); GLOBAL_DEF("debug/settings/profiler/max_functions", 16384); custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1"); diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h index 7861c76153..0012cea72d 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -498,6 +498,11 @@ public: flush_one(); } + _FORCE_INLINE_ void flush_if_pending() { + if (unlikely(read_ptr_and_epoch != write_ptr_and_epoch)) { + flush_all(); + } + } void flush_all() { //ERR_FAIL_COND(sync); lock(); diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h index d26c445eb4..3edc73b1a9 100644 --- a/core/templates/rid_owner.h +++ b/core/templates/rid_owner.h @@ -79,8 +79,7 @@ class RID_Alloc : public RID_AllocBase { SpinLock spin_lock; -public: - RID make_rid(const T &p_value) { + _FORCE_INLINE_ RID _allocate_rid(const T *p_initializer) { if (THREAD_SAFE) { spin_lock.lock(); } @@ -115,15 +114,22 @@ public: uint32_t free_chunk = free_index / elements_in_chunk; uint32_t free_element = free_index % elements_in_chunk; - T *ptr = &chunks[free_chunk][free_element]; - memnew_placement(ptr, T(p_value)); + if (p_initializer) { + T *ptr = &chunks[free_chunk][free_element]; + memnew_placement(ptr, T(*p_initializer)); + } - uint32_t validator = (uint32_t)(_gen_id() & 0xFFFFFFFF); + uint32_t validator = (uint32_t)(_gen_id() & 0x7FFFFFFF); uint64_t id = validator; id <<= 32; id |= free_index; validator_chunks[free_chunk][free_element] = validator; + + if (!p_initializer) { + validator_chunks[free_chunk][free_element] |= 0x80000000; //mark uninitialized bit + } + alloc_count++; if (THREAD_SAFE) { @@ -133,7 +139,20 @@ public: return _make_from_id(id); } - _FORCE_INLINE_ T *getornull(const RID &p_rid) { +public: + RID make_rid(const T &p_value) { + return _allocate_rid(&p_value); + } + + //allocate but don't initialize, use initialize_rid afterwards + RID allocate_rid() { + return _allocate_rid(nullptr); + } + + _FORCE_INLINE_ T *getornull(const RID &p_rid, bool p_initialize = false) { + if (p_rid == RID()) { + return nullptr; + } if (THREAD_SAFE) { spin_lock.lock(); } @@ -151,10 +170,32 @@ public: uint32_t idx_element = idx % elements_in_chunk; uint32_t validator = uint32_t(id >> 32); - if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) { + + if (unlikely(p_initialize)) { + if (unlikely(!(validator_chunks[idx_chunk][idx_element] & 0x80000000))) { + if (THREAD_SAFE) { + spin_lock.unlock(); + } + ERR_FAIL_V_MSG(nullptr, "Initializing already initialized RID"); + } + + if (unlikely((validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) != validator)) { + if (THREAD_SAFE) { + spin_lock.unlock(); + } + ERR_FAIL_V_MSG(nullptr, "Attempting to initialize the wrong RID"); + return nullptr; + } + + validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF; //initialized + + } else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) { if (THREAD_SAFE) { spin_lock.unlock(); } + if (validator_chunks[idx_chunk][idx_element] & 0x80000000) { + ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID"); + } return nullptr; } @@ -166,6 +207,11 @@ public: return ptr; } + void initialize_rid(RID p_rid, const T &p_value) { + T *mem = getornull(p_rid, true); + ERR_FAIL_COND(!mem); + memnew_placement(mem, T(p_value)); + } _FORCE_INLINE_ bool owns(const RID &p_rid) { if (THREAD_SAFE) { @@ -186,7 +232,7 @@ public: uint32_t validator = uint32_t(id >> 32); - bool owned = validator_chunks[idx_chunk][idx_element] == validator; + bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator; if (THREAD_SAFE) { spin_lock.unlock(); @@ -213,7 +259,12 @@ public: uint32_t idx_element = idx % elements_in_chunk; uint32_t validator = uint32_t(id >> 32); - if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) { + if (unlikely(validator_chunks[idx_chunk][idx_element] & 0x80000000)) { + if (THREAD_SAFE) { + spin_lock.unlock(); + } + ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID"); + } else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) { if (THREAD_SAFE) { spin_lock.unlock(); } @@ -330,6 +381,14 @@ public: return alloc.make_rid(p_ptr); } + _FORCE_INLINE_ RID allocate_rid() { + return alloc.allocate_rid(); + } + + _FORCE_INLINE_ void initialize_rid(RID p_rid, T *p_ptr) { + alloc.initialize_rid(p_rid, p_ptr); + } + _FORCE_INLINE_ T *getornull(const RID &p_rid) { T **ptr = alloc.getornull(p_rid); if (unlikely(!ptr)) { @@ -338,6 +397,12 @@ public: return *ptr; } + _FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) { + T **ptr = alloc.getornull(p_rid); + ERR_FAIL_COND(!ptr); + *ptr = p_new_ptr; + } + _FORCE_INLINE_ bool owns(const RID &p_rid) { return alloc.owns(p_rid); } @@ -379,6 +444,14 @@ public: return alloc.make_rid(p_ptr); } + _FORCE_INLINE_ RID allocate_rid() { + return alloc.allocate_rid(); + } + + _FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) { + alloc.initialize_rid(p_rid, p_ptr); + } + _FORCE_INLINE_ T *getornull(const RID &p_rid) { return alloc.getornull(p_rid); } |