diff --git a/MobileGL/MG_Backend/DirectVulkan/MagmaSession.cpp b/MobileGL/MG_Backend/DirectVulkan/MagmaSession.cpp index 7f22897f..449700f9 100644 --- a/MobileGL/MG_Backend/DirectVulkan/MagmaSession.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/MagmaSession.cpp @@ -26,11 +26,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { std::atomic 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(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 diff --git a/MobileGL/MG_Backend/DirectVulkan/MagmaSession.h b/MobileGL/MG_Backend/DirectVulkan/MagmaSession.h index bea6597f..cbf63ff0 100644 --- a/MobileGL/MG_Backend/DirectVulkan/MagmaSession.h +++ b/MobileGL/MG_Backend/DirectVulkan/MagmaSession.h @@ -34,9 +34,19 @@ namespace MobileGL::MG_Backend::DirectVulkan { using SessionLocalDestroy = void (*)(void*); // Registers one SessionLocal 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 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);