Skip to content

Commit

Permalink
Add RID reservation infrastructure
Browse files Browse the repository at this point in the history
  • Loading branch information
RandomShaper committed Feb 5, 2021
1 parent f66b4f2 commit f6d6dad
Show file tree
Hide file tree
Showing 27 changed files with 674 additions and 471 deletions.
136 changes: 103 additions & 33 deletions core/templates/rid_owner.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,7 @@ class RID_Alloc : public RID_AllocBase {

SpinLock spin_lock;

public:
RID make_rid(const T &p_value) {
if (THREAD_SAFE) {
spin_lock.lock();
}

uint64_t _allocate_element(T **r_ptr = nullptr) {
if (alloc_count == max_alloc) {
//allocate a new chunk
uint32_t chunk_count = alloc_count == 0 ? 0 : (max_alloc / elements_in_chunk);
Expand Down Expand Up @@ -115,29 +110,24 @@ class RID_Alloc : public RID_AllocBase {
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));

//keep MSB as a flag meaning reserved (allocated, but not initialized)
uint32_t validator = (uint32_t)(_gen_id() & 0xFFFFFFFF);
uint64_t id = validator;
id <<= 32;
id |= free_index;
uint64_t id = (uint64_t(validator) << 32) | free_index;

if (r_ptr) {
*r_ptr = &chunks[free_chunk][free_element];
} else {
//only reserving
validator |= 0x80000000;
}
validator_chunks[free_chunk][free_element] = validator;
alloc_count++;

if (THREAD_SAFE) {
spin_lock.unlock();
}

return _make_from_id(id);
return id;
}

_FORCE_INLINE_ T *getornull(const RID &p_rid) {
if (THREAD_SAFE) {
spin_lock.lock();
}

template <bool FOR_RESERVED = false>
_FORCE_INLINE_ T *_getornull(const RID &p_rid) {
uint64_t id = p_rid.get_id();
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
if (unlikely(idx >= max_alloc)) {
Expand All @@ -151,14 +141,72 @@ class RID_Alloc : public RID_AllocBase {
uint32_t idx_element = idx % elements_in_chunk;

uint32_t validator = uint32_t(id >> 32);
if (FOR_RESERVED) {
validator |= 0x80000000;
}
if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
return nullptr;
}
if (FOR_RESERVED) {
//mark now as initialized
validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF;
}

return &chunks[idx_chunk][idx_element];
}

public:
RID make_rid(const T &p_value, RID p_reserved_rid) {
if (THREAD_SAFE) {
spin_lock.lock();
}

RID rid;
T *ptr;
if (p_reserved_rid.is_null()) {
uint64_t id = _allocate_element(&ptr);
memnew_placement(ptr, T(p_value));
rid = _make_from_id(id);
} else {
ptr = _getornull<true>(p_reserved_rid);
if (likely(ptr)) { //otherwise, reserved RID not found!
memnew_placement(ptr, T(p_value));
rid = p_reserved_rid;
}
}

if (THREAD_SAFE) {
spin_lock.unlock();
}

ERR_FAIL_COND_V(!ptr, RID());

return rid;
}

RID reserve_rid() {
if (THREAD_SAFE) {
spin_lock.lock();
}

uint64_t id = _allocate_element();

if (THREAD_SAFE) {
spin_lock.unlock();
}

return _make_from_id(id);
}

_FORCE_INLINE_ T *getornull(const RID &p_rid) {
if (THREAD_SAFE) {
spin_lock.lock();
}

T *ptr = &chunks[idx_chunk][idx_element];
T *ptr = _getornull(p_rid);

if (THREAD_SAFE) {
spin_lock.unlock();
Expand Down Expand Up @@ -186,7 +234,8 @@ class RID_Alloc : public RID_AllocBase {

uint32_t validator = uint32_t(id >> 32);

bool owned = validator_chunks[idx_chunk][idx_element] == validator;
//considering reserved RIDs are owned
bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;

if (THREAD_SAFE) {
spin_lock.unlock();
Expand All @@ -213,14 +262,17 @@ class RID_Alloc : public RID_AllocBase {
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] & 0x7FFFFFFF) != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
ERR_FAIL();
}

chunks[idx_chunk][idx_element].~T();
//destruct only if initialized (not only reserved)
if (!(validator_chunks[idx_chunk][idx_element] & 0x80000000)) {
chunks[idx_chunk][idx_element].~T();
}
validator_chunks[idx_chunk][idx_element] = 0xFFFFFFFF; // go invalid

alloc_count--;
Expand All @@ -242,9 +294,16 @@ class RID_Alloc : public RID_AllocBase {
}
uint64_t idx = free_list_chunks[p_index / elements_in_chunk][p_index % elements_in_chunk];
T *ptr = &chunks[idx / elements_in_chunk][idx % elements_in_chunk];
#ifdef DEBUG_ENABLED
uint64_t validator = validator_chunks[idx / elements_in_chunk][idx % elements_in_chunk];
#endif
if (THREAD_SAFE) {
spin_lock.unlock();
}
#ifdef DEBUG_ENABLED
//reserved, but not initialized
ERR_FAIL_COND_V(validator & 0x80000000, nullptr);
#endif
return ptr;
}

Expand All @@ -256,7 +315,7 @@ class RID_Alloc : public RID_AllocBase {
uint64_t idx = free_list_chunks[p_index / elements_in_chunk][p_index % elements_in_chunk];
uint64_t validator = validator_chunks[idx / elements_in_chunk][idx % elements_in_chunk];

RID rid = _make_from_id((validator << 32) | idx);
RID rid = _make_from_id(((validator & 0x7FFFFFFF) << 32) | idx);
if (THREAD_SAFE) {
spin_lock.unlock();
}
Expand All @@ -270,7 +329,7 @@ class RID_Alloc : public RID_AllocBase {
for (size_t i = 0; i < max_alloc; i++) {
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
if (validator != 0xFFFFFFFF) {
p_owned->push_back(_make_from_id((validator << 32) | i));
p_owned->push_back(_make_from_id(((validator & 0x7FFFFFFF) << 32) | i));
}
}
if (THREAD_SAFE) {
Expand Down Expand Up @@ -300,7 +359,8 @@ class RID_Alloc : public RID_AllocBase {

for (size_t i = 0; i < max_alloc; i++) {
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
if (validator != 0xFFFFFFFF) {
//destruct only if initialized (not only reserved)
if (validator != 0xFFFFFFFF && !(validator & 0x80000000)) {
chunks[i / elements_in_chunk][i % elements_in_chunk].~T();
}
}
Expand All @@ -326,8 +386,13 @@ class RID_PtrOwner {
RID_Alloc<T *, THREAD_SAFE> alloc;

public:
_FORCE_INLINE_ RID make_rid(T *p_ptr) {
return alloc.make_rid(p_ptr);
template <bool VALID = THREAD_SAFE> //only safe for multithreaded servers if this is thread-safe itself
_FORCE_INLINE_ RID reserve_rid(typename std::enable_if<VALID, int>::type = 0) {
return alloc.reserve_rid();
}

_FORCE_INLINE_ RID make_rid(T *p_ptr, RID p_reserved_rid = RID()) {
return alloc.make_rid(p_ptr, p_reserved_rid);
}

_FORCE_INLINE_ T *getornull(const RID &p_rid) {
Expand Down Expand Up @@ -375,8 +440,13 @@ class RID_Owner {
RID_Alloc<T, THREAD_SAFE> alloc;

public:
_FORCE_INLINE_ RID make_rid(const T &p_ptr) {
return alloc.make_rid(p_ptr);
template <bool VALID = THREAD_SAFE> //only safe for multithreaded servers if this is thread-safe itself
_FORCE_INLINE_ RID reserve_rid(typename std::enable_if<VALID, int>::type = 0) {
return alloc.reserve_rid();
}

_FORCE_INLINE_ RID make_rid(const T &p_value, RID p_reserved_rid = RID()) {
return alloc.make_rid(p_value, p_reserved_rid);
}

_FORCE_INLINE_ T *getornull(const RID &p_rid) {
Expand Down
7 changes: 4 additions & 3 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1570,9 +1570,10 @@ Error Main::setup2(Thread::ID p_main_tid_override) {

/* Initialize Visual Server */

rendering_server = memnew(RenderingServerDefault);
if (OS::get_singleton()->get_render_thread_mode() != OS::RENDER_THREAD_UNSAFE) {
rendering_server = memnew(RenderingServerWrapMT(rendering_server,
if (OS::get_singleton()->get_render_thread_mode() == OS::RENDER_THREAD_UNSAFE) {
rendering_server = memnew(RenderingServerDefault);
} else {
rendering_server = memnew(RenderingServerWrapMT(memnew(RenderingServerDefault),
OS::get_singleton()->get_render_thread_mode() ==
OS::RENDER_SEPARATE_THREAD));
}
Expand Down
7 changes: 4 additions & 3 deletions platform/uwp/os_uwp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,11 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a

set_video_mode(vm);

rendering_server = memnew(RenderingServerDefault);
// FIXME: Reimplement threaded rendering
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
rendering_server = memnew(RenderingServerWrapMT(rendering_server, false));
if (get_render_thread_mode() == RENDER_THREAD_UNSAFE) {
rendering_server = memnew(RenderingServerDefault);
} else {
rendering_server = memnew(RenderingServerWrapMT(memnew(RenderingServerDefault), false);
}

rendering_server->init();
Expand Down
48 changes: 24 additions & 24 deletions servers/physics_2d/physics_server_2d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
#define FLUSH_QUERY_CHECK(m_object) \
ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead.");

RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) {
RID PhysicsServer2DSW::_shape_create(ShapeType p_shape, RID p_reserved_rid) {
Shape2DSW *shape = nullptr;
switch (p_shape) {
case SHAPE_LINE: {
Expand Down Expand Up @@ -73,42 +73,42 @@ RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) {
} break;
}

RID id = shape_owner.make_rid(shape);
RID id = shape_owner.make_rid(shape, p_reserved_rid);
shape->set_self(id);

return id;
}

RID PhysicsServer2DSW::line_shape_create() {
return _shape_create(SHAPE_LINE);
RID PhysicsServer2DSW::line_shape_create_reserved(RID p_reserved_rid) {
return _shape_create(SHAPE_LINE, p_reserved_rid);
}

RID PhysicsServer2DSW::ray_shape_create() {
return _shape_create(SHAPE_RAY);
RID PhysicsServer2DSW::ray_shape_create_reserved(RID p_reserved_rid) {
return _shape_create(SHAPE_RAY, p_reserved_rid);
}

RID PhysicsServer2DSW::segment_shape_create() {
return _shape_create(SHAPE_SEGMENT);
RID PhysicsServer2DSW::segment_shape_create_reserved(RID p_reserved_rid) {
return _shape_create(SHAPE_SEGMENT, p_reserved_rid);
}

RID PhysicsServer2DSW::circle_shape_create() {
return _shape_create(SHAPE_CIRCLE);
RID PhysicsServer2DSW::circle_shape_create_reserved(RID p_reserved_rid) {
return _shape_create(SHAPE_CIRCLE, p_reserved_rid);
}

RID PhysicsServer2DSW::rectangle_shape_create() {
return _shape_create(SHAPE_RECTANGLE);
RID PhysicsServer2DSW::rectangle_shape_create_reserved(RID p_reserved_rid) {
return _shape_create(SHAPE_RECTANGLE, p_reserved_rid);
}

RID PhysicsServer2DSW::capsule_shape_create() {
return _shape_create(SHAPE_CAPSULE);
RID PhysicsServer2DSW::capsule_shape_create_reserved(RID p_reserved_rid) {
return _shape_create(SHAPE_CAPSULE, p_reserved_rid);
}

RID PhysicsServer2DSW::convex_polygon_shape_create() {
return _shape_create(SHAPE_CONVEX_POLYGON);
RID PhysicsServer2DSW::convex_polygon_shape_create_reserved(RID p_reserved_rid) {
return _shape_create(SHAPE_CONVEX_POLYGON, p_reserved_rid);
}

RID PhysicsServer2DSW::concave_polygon_shape_create() {
return _shape_create(SHAPE_CONCAVE_POLYGON);
RID PhysicsServer2DSW::concave_polygon_shape_create_reserved(RID p_reserved_rid) {
return _shape_create(SHAPE_CONCAVE_POLYGON, p_reserved_rid);
}

void PhysicsServer2DSW::shape_set_data(RID p_shape, const Variant &p_data) {
Expand Down Expand Up @@ -213,9 +213,9 @@ bool PhysicsServer2DSW::shape_collide(RID p_shape_A, const Transform2D &p_xform_
return res;
}

RID PhysicsServer2DSW::space_create() {
RID PhysicsServer2DSW::space_create_reserved(RID p_reserved_rid) {
Space2DSW *space = memnew(Space2DSW);
RID id = space_owner.make_rid(space);
RID id = space_owner.make_rid(space, p_reserved_rid);
space->set_self(id);
RID area_id = area_create();
Area2DSW *area = area_owner.getornull(area_id);
Expand Down Expand Up @@ -283,9 +283,9 @@ PhysicsDirectSpaceState2D *PhysicsServer2DSW::space_get_direct_state(RID p_space
return space->get_direct_state();
}

RID PhysicsServer2DSW::area_create() {
RID PhysicsServer2DSW::area_create_reserved(RID p_reserved_rid) {
Area2DSW *area = memnew(Area2DSW);
RID rid = area_owner.make_rid(area);
RID rid = area_owner.make_rid(area, p_reserved_rid);
area->set_self(rid);
return rid;
};
Expand Down Expand Up @@ -528,9 +528,9 @@ void PhysicsServer2DSW::area_set_area_monitor_callback(RID p_area, Object *p_rec

/* BODY API */

RID PhysicsServer2DSW::body_create() {
RID PhysicsServer2DSW::body_create_reserved(RID p_reserved_rid) {
Body2DSW *body = memnew(Body2DSW);
RID rid = body_owner.make_rid(body);
RID rid = body_owner.make_rid(body, p_reserved_rid);
body->set_self(rid);
return rid;
}
Expand Down
Loading

0 comments on commit f6d6dad

Please sign in to comment.