mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
TLS: the Magma session read and built-slot lookup inline into SessionLocal accesses.
This commit is contained in:
@@ -26,11 +26,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
std::atomic<Uint64> g_nextSessionId{1};
|
||||
|
||||
thread_local MagmaSession* t_boundSession = nullptr;
|
||||
|
||||
// Leak-at-exit, like the renderer it holds (GlobalObjects.cpp): nothing may tear the
|
||||
// monolith's renderer down from a static destructor after the driver is gone.
|
||||
MagmaSession& ProcessSession() {
|
||||
MagmaSession& ProcessSessionInstance() {
|
||||
static auto* session = new MagmaSession();
|
||||
return *session;
|
||||
}
|
||||
@@ -42,12 +40,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return static_cast<Uint32>(registry.size() - 1);
|
||||
}
|
||||
|
||||
MagmaSession& Detail::CurrentMagmaSession() {
|
||||
MagmaSession* bound = t_boundSession;
|
||||
return bound != nullptr ? *bound : ProcessSession();
|
||||
}
|
||||
MagmaSession& Detail::ProcessMagmaSession() { return ProcessSessionInstance(); }
|
||||
|
||||
void* Detail::SessionLocalSlot(MagmaSession& session, Uint32 index) {
|
||||
void* Detail::SessionLocalSlotSlow(MagmaSession& session, Uint32 index) {
|
||||
if (index >= session.m_slots.size()) session.m_slots.resize(Registry().size(), nullptr);
|
||||
void*& slot = session.m_slots[index];
|
||||
if (slot == nullptr) slot = Registry()[index].construct();
|
||||
@@ -63,25 +58,25 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
MagmaSession::~MagmaSession() {
|
||||
MagmaSession* const previous = t_boundSession;
|
||||
t_boundSession = this;
|
||||
MagmaSession* const previous = Detail::t_boundMagmaSession;
|
||||
Detail::t_boundMagmaSession = this;
|
||||
const auto& registry = Registry();
|
||||
for (SizeT i = m_slots.size(); i-- > 0;) {
|
||||
if (m_slots[i] != nullptr) registry[i].destroy(m_slots[i]);
|
||||
m_slots[i] = nullptr;
|
||||
}
|
||||
// Never back to this session: it is gone.
|
||||
t_boundSession = previous == this ? nullptr : previous;
|
||||
Detail::t_boundMagmaSession = previous == this ? nullptr : previous;
|
||||
}
|
||||
|
||||
MagmaSessionScope::MagmaSessionScope(MagmaSession* session) : m_previous(t_boundSession) {
|
||||
t_boundSession = session;
|
||||
MagmaSessionScope::MagmaSessionScope(MagmaSession* session) : m_previous(Detail::t_boundMagmaSession) {
|
||||
Detail::t_boundMagmaSession = session;
|
||||
}
|
||||
|
||||
MagmaSessionScope::~MagmaSessionScope() { t_boundSession = m_previous; }
|
||||
MagmaSessionScope::~MagmaSessionScope() { Detail::t_boundMagmaSession = m_previous; }
|
||||
|
||||
void BindMagmaSessionToThisThread(MagmaSession* session) { t_boundSession = session; }
|
||||
void BindMagmaSessionToThisThread(MagmaSession* session) { Detail::t_boundMagmaSession = session; }
|
||||
|
||||
MagmaSession* BoundMagmaSession() { return t_boundSession; }
|
||||
MagmaSession* BoundMagmaSession() { return Detail::t_boundMagmaSession; }
|
||||
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -34,9 +34,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
using SessionLocalDestroy = void (*)(void*);
|
||||
// Registers one SessionLocal<T> and returns its slot. Called from static initialization.
|
||||
Uint32 RegisterSessionLocal(SessionLocalConstruct construct, SessionLocalDestroy destroy);
|
||||
// The calling thread's bound session (MagmaSessionScope, BindMagmaSessionToThisThread), null
|
||||
// when it has none. P15: visible here, and constant-initialized, so the read inlines into
|
||||
// every SessionLocal access and one function's accesses can share a single TLS address
|
||||
// computation instead of paying one out-of-line call each.
|
||||
inline constinit thread_local MagmaSession* t_boundMagmaSession = nullptr;
|
||||
MagmaSession& ProcessMagmaSession();
|
||||
// The calling thread's session, or the process-wide default.
|
||||
MagmaSession& CurrentMagmaSession();
|
||||
void* SessionLocalSlot(MagmaSession& session, Uint32 index);
|
||||
inline MagmaSession& CurrentMagmaSession() {
|
||||
MagmaSession* const bound = t_boundMagmaSession;
|
||||
return bound != nullptr ? *bound : ProcessMagmaSession();
|
||||
}
|
||||
inline void* SessionLocalSlot(MagmaSession& session, Uint32 index);
|
||||
void* SessionLocalSlotSlow(MagmaSession& session, Uint32 index);
|
||||
} // namespace Detail
|
||||
|
||||
// One served session's copy of every SessionLocal. Slots are built lazily on first use and
|
||||
@@ -55,12 +65,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
private:
|
||||
friend void* Detail::SessionLocalSlot(MagmaSession& session, Uint32 index);
|
||||
friend void* Detail::SessionLocalSlotSlow(MagmaSession& session, Uint32 index);
|
||||
Vector<void*> m_slots;
|
||||
Uint64 m_id = 0;
|
||||
};
|
||||
|
||||
// Makes `session` the calling thread's Magma session for the scope's lifetime, restoring the
|
||||
// previous binding (usually none) afterwards.
|
||||
// A built slot is returned in line; a missing one is built out of line.
|
||||
inline void* Detail::SessionLocalSlot(MagmaSession& session, Uint32 index) {
|
||||
if (index < session.m_slots.size()) {
|
||||
if (void* const slot = session.m_slots[index]) return slot;
|
||||
}
|
||||
return SessionLocalSlotSlow(session, index);
|
||||
}
|
||||
|
||||
class MagmaSessionScope {
|
||||
public:
|
||||
explicit MagmaSessionScope(MagmaSession* session);
|
||||
|
||||
Reference in New Issue
Block a user