diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 696b0c83..05df1b67 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -98,7 +98,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject.get()); Bool exist = (backendBufferIt != g_backendBufferObjects.end()); - auto& backendObj = exist ? backendBufferIt->second : g_backendBufferObjects[bufferObject.get()]; + auto& backendObj = exist ? backendBufferIt->second : g_backendBufferObjects.GetOrCreate(bufferObject); if (!exist) { backendObj = MakeShared(); } @@ -109,6 +109,8 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif + g_backendBufferObjects.CollectGarbageIfNeeded(); + // All buffers we need are: // 1.VBO 2.IBO (if needed) 3.UBO 4.IndirectBuffer (if needed) 5.SSBO (TODO) // PBO is not needed since it should be handled in frontend @@ -162,6 +164,8 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif + g_backendVertexArrayObjects.CollectGarbageIfNeeded(); + auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray(); if (!currentVAOObject) { MGLOG_E("No VAO is currently bound, cannot sync current VAO."); @@ -170,7 +174,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const auto& backendVAOIt = g_backendVertexArrayObjects.find(currentVAOObject.get()); Bool exist = (backendVAOIt != g_backendVertexArrayObjects.end()); - auto& backendObj = exist ? backendVAOIt->second : g_backendVertexArrayObjects[currentVAOObject.get()]; + auto& backendObj = exist ? backendVAOIt->second : g_backendVertexArrayObjects.GetOrCreate(currentVAOObject); if (!exist) { backendObj = MakeShared(); } @@ -186,7 +190,7 @@ namespace MobileGL::MG_Backend::DirectGLES { #endif const auto& backendTextureIt = g_backendTextureObjects.find(textureObject.get()); Bool exist = (backendTextureIt != g_backendTextureObjects.end()); - auto& backendObj = exist ? backendTextureIt->second : g_backendTextureObjects[textureObject.get()]; + auto& backendObj = exist ? backendTextureIt->second : g_backendTextureObjects.GetOrCreate(textureObject); if (!exist) { backendObj = MakeShared(); } @@ -201,6 +205,8 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif + g_backendTextureObjects.CollectGarbageIfNeeded(); + // All textures we need are: // 1. textures bound to texture units (TODO: only sync ones that are used in current program) // 2. textures used in current FBO @@ -235,6 +241,10 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif + g_backendFramebufferObjects.CollectGarbageIfNeeded(); + TextureImpl::g_backendTextureObjects.CollectGarbageIfNeeded(); + RenderbufferImpl::g_backendRenderbufferObjects.CollectGarbageIfNeeded(); + const FramebufferTarget fboTargets[] = {FramebufferTarget::Draw, FramebufferTarget::Read}; MG_State::GLState::FramebufferObject* lastUpdatedFBO = nullptr; @@ -263,7 +273,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const auto& backendFBOIt = g_backendFramebufferObjects.find(currentFBO.get()); Bool exist = (backendFBOIt != g_backendFramebufferObjects.end()); - auto& backendObj = exist ? backendFBOIt->second : g_backendFramebufferObjects[currentFBO.get()]; + auto& backendObj = exist ? backendFBOIt->second : g_backendFramebufferObjects.GetOrCreate(currentFBO); if (!exist) { backendObj = MakeShared(); } @@ -457,6 +467,9 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif + g_backendProgramObjects.CollectGarbageIfNeeded(); + SamplerImpl::g_backendSamplerObjects.CollectGarbageIfNeeded(); + auto& currentProgram = MG_State::pGLContext->GetCurrentProgram(); if (!currentProgram || !currentProgram->GetLinkStatus()) { g_GLESFuncs.glUseProgram(0); @@ -464,7 +477,7 @@ namespace MobileGL::MG_Backend::DirectGLES { } const auto& backendProgramIt = g_backendProgramObjects.find(currentProgram.get()); Bool exist = (backendProgramIt != g_backendProgramObjects.end()); - auto& backendObj = exist ? backendProgramIt->second : g_backendProgramObjects[currentProgram.get()]; + auto& backendObj = exist ? backendProgramIt->second : g_backendProgramObjects.GetOrCreate(currentProgram); if (!exist) { backendObj = MakeShared(); backendObj->SyncToBackend(currentProgram); @@ -657,7 +670,7 @@ namespace MobileGL::MG_Backend::DirectGLES { SamplerImpl::g_backendSamplerObjects.find(samplerObject.get()); Bool exist = (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end()); auto& backendObj = exist ? backendSamplerIt->second - : SamplerImpl::g_backendSamplerObjects[samplerObject.get()]; + : SamplerImpl::g_backendSamplerObjects.GetOrCreate(samplerObject); if (!exist) { backendObj = MakeShared(); } @@ -887,7 +900,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get()); Bool exist = (backendTextureIt != TextureImpl::g_backendTextureObjects.end()); auto& backendObj = - exist ? backendTextureIt->second : TextureImpl::g_backendTextureObjects[textureObject.get()]; + exist ? backendTextureIt->second : TextureImpl::g_backendTextureObjects.GetOrCreate(textureObject); if (!exist) { backendObj = MakeShared(); } diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 8eb363c0..838bbf10 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -189,7 +189,7 @@ namespace MobileGL::MG_Backend::DirectGLES { g_GLESFuncs.glBindBuffer(target, m_backendBufferId); } - UnorderedMap> g_backendBufferObjects; + StateBackendObjectRegistry g_backendBufferObjects; BackendBufferObject* g_boundVertexBufferObject = nullptr; } // namespace BufferImpl @@ -301,7 +301,7 @@ namespace MobileGL::MG_Backend::DirectGLES { m_syncedAttributeVersions = allAttributeVersions; } - UnorderedMap> + StateBackendObjectRegistry g_backendVertexArrayObjects; } // namespace VertexArrayImpl @@ -531,8 +531,11 @@ namespace MobileGL::MG_Backend::DirectGLES { SharedPtr backendBufferObject; const auto& backendBufferIt = backendBuffers.find(buffer.get()); if (backendBufferIt == backendBuffers.end()) { - backendBufferObject = MakeShared(); - backendBuffers[buffer.get()] = backendBufferObject; + auto& backendBufferSlot = backendBuffers.GetOrCreate(buffer); + if (!backendBufferSlot) { + backendBufferSlot = MakeShared(); + } + backendBufferObject = backendBufferSlot; } else { backendBufferObject = backendBufferIt->second; } @@ -760,7 +763,7 @@ namespace MobileGL::MG_Backend::DirectGLES { Array, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> g_boundTexturesCache; - UnorderedMap> g_backendTextureObjects; + StateBackendObjectRegistry g_backendTextureObjects; } // namespace TextureImpl namespace FramebufferImpl { @@ -809,9 +812,12 @@ namespace MobileGL::MG_Backend::DirectGLES { RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject.get()); SharedPtr backendRenderbufferObject; if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) { - backendRenderbufferObject = MakeShared(); - RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject.get()] = - backendRenderbufferObject; + auto& backendRenderbufferSlot = + RenderbufferImpl::g_backendRenderbufferObjects.GetOrCreate(renderbufferObject); + if (!backendRenderbufferSlot) { + backendRenderbufferSlot = MakeShared(); + } + backendRenderbufferObject = backendRenderbufferSlot; } else { backendRenderbufferObject = backendRenderbufferIt->second; } @@ -976,13 +982,13 @@ namespace MobileGL::MG_Backend::DirectGLES { return glBackendReadBuffer; } - UnorderedMap> + StateBackendObjectRegistry g_backendFramebufferObjects; Array g_fboBindVersions = {0}; } // namespace FramebufferImpl namespace PrgramImpl { - UnorderedMap> g_backendProgramObjects; + StateBackendObjectRegistry g_backendProgramObjects; BackendProgramObjectImpl::BackendProgramObjectImpl() { #ifdef TRACY_ENABLE @@ -1273,7 +1279,7 @@ namespace MobileGL::MG_Backend::DirectGLES { } Array g_boundSamplersCache; - UnorderedMap> g_backendSamplerObjects; + StateBackendObjectRegistry g_backendSamplerObjects; } // namespace SamplerImpl namespace RenderbufferImpl { @@ -1335,7 +1341,7 @@ namespace MobileGL::MG_Backend::DirectGLES { MGLOG_D("RBO %u sync completed. backend ID %u", stateRBOObject->GetExternalIndex(), m_backendRBOId); } - UnorderedMap> + StateBackendObjectRegistry g_backendRenderbufferObjects; } // namespace RenderbufferImpl } // namespace MobileGL::MG_Backend::DirectGLES diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h index e82e50fb..9f58bfe6 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.h +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -15,6 +15,87 @@ #include namespace MobileGL::MG_Backend::DirectGLES { + template + class StateBackendObjectRegistry { + public: + using StatePtr = SharedPtr; + using StateWeakPtr = std::weak_ptr; + using BackendPtr = SharedPtr; + using BackendMap = UnorderedMap; + using StateRefMap = UnorderedMap; + using iterator = typename BackendMap::iterator; + using const_iterator = typename BackendMap::const_iterator; + + BackendPtr& GetOrCreate(const StatePtr& stateObj) { + MOBILEGL_ASSERT(stateObj != nullptr, "State object must not be null"); + + auto* key = stateObj.get(); + auto trackedStateIt = m_stateRefs.find(key); + if (trackedStateIt != m_stateRefs.end() && trackedStateIt->second.expired()) { + EraseByKey(key); + } + m_stateRefs[key] = stateObj; + return m_backendObjects[key]; + } + + iterator find(StateObject* stateObj) { + if (!IsAlive(stateObj)) { + EraseByKey(stateObj); + return m_backendObjects.end(); + } + return m_backendObjects.find(stateObj); + } + + const_iterator find(StateObject* stateObj) const { + return const_cast(this)->find(stateObj); + } + + iterator end() { return m_backendObjects.end(); } + const_iterator end() const { return m_backendObjects.end(); } + + void CollectGarbageIfNeeded() { + ++m_gcTick; + if (m_gcTick < kGCInterval) { + return; + } + CollectGarbage(); + m_gcTick = 0; + } + + void CollectGarbageNow() { CollectGarbage(); } + + private: + bool IsAlive(StateObject* stateObj) const { + const auto trackedStateIt = m_stateRefs.find(stateObj); + if (trackedStateIt == m_stateRefs.end()) { + return false; + } + return !trackedStateIt->second.expired(); + } + + void EraseByKey(StateObject* stateObj) { + m_stateRefs.erase(stateObj); + m_backendObjects.erase(stateObj); + } + + void CollectGarbage() { + for (auto trackedStateIt = m_stateRefs.begin(); trackedStateIt != m_stateRefs.end();) { + if (trackedStateIt->second.expired()) { + m_backendObjects.erase(trackedStateIt->first); + trackedStateIt = m_stateRefs.erase(trackedStateIt); + } else { + ++trackedStateIt; + } + } + } + + private: + static constexpr Uint32 kGCInterval = 1024; + StateRefMap m_stateRefs; + BackendMap m_backendObjects; + Uint32 m_gcTick = 0; + }; + namespace BufferImpl { const GLenum TempBufferTarget = GL_ARRAY_BUFFER; class BackendBufferObject { @@ -36,7 +117,7 @@ namespace MobileGL::MG_Backend::DirectGLES { }; extern BackendBufferObject* g_boundVertexBufferObject; - extern UnorderedMap> g_backendBufferObjects; + extern StateBackendObjectRegistry g_backendBufferObjects; } // namespace BufferImpl namespace VertexArrayImpl { @@ -55,7 +136,7 @@ namespace MobileGL::MG_Backend::DirectGLES { m_syncedAttributeVersions; }; - extern UnorderedMap> + extern StateBackendObjectRegistry g_backendVertexArrayObjects; } // namespace VertexArrayImpl @@ -110,7 +191,7 @@ namespace MobileGL::MG_Backend::DirectGLES { void ActivateTextureUnit(Uint unit); void UnbindTexture(Uint unit, GLenum target); - extern UnorderedMap> + extern StateBackendObjectRegistry g_backendTextureObjects; extern Array, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> @@ -153,7 +234,7 @@ namespace MobileGL::MG_Backend::DirectGLES { FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0}; }; - extern UnorderedMap> + extern StateBackendObjectRegistry g_backendFramebufferObjects; extern Array g_fboBindVersions; } // namespace FramebufferImpl @@ -174,7 +255,7 @@ namespace MobileGL::MG_Backend::DirectGLES { Bool m_isInitialized = false; }; - extern UnorderedMap> + extern StateBackendObjectRegistry g_backendProgramObjects; } // namespace PrgramImpl @@ -197,7 +278,8 @@ namespace MobileGL::MG_Backend::DirectGLES { extern Array g_boundSamplersCache; - extern UnorderedMap> g_backendSamplerObjects; + extern StateBackendObjectRegistry + g_backendSamplerObjects; } // namespace SamplerImpl namespace RenderbufferImpl { @@ -216,7 +298,7 @@ namespace MobileGL::MG_Backend::DirectGLES { Int m_cacheHeight = 0; }; - extern UnorderedMap> + extern StateBackendObjectRegistry g_backendRenderbufferObjects; } // namespace RenderbufferImpl } // namespace MobileGL::MG_Backend::DirectGLES