From 340449b77e87038d8692d998f7295a4efbb1aa1e Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 12 Jul 2026 04:31:34 -0400 Subject: [PATCH] [Perf] (MG_State, MG_Backend/DirectGLES): skip never-touched buffer bind points via high-water mark; SyncNeccessaryBuffers 15.7% -> 4.2% --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 4 +++- MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp | 2 ++ .../MG_State/GLState/BufferState/BufferState.cpp | 3 +++ .../MG_State/GLState/BufferState/BufferState.h | 15 +++++++++++++++ MobileGL/MG_State/GLState/Core.h | 6 ++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index d58ddb31..2780dcc5 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -201,7 +201,9 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif - auto bindingPointCnt = MG_State::pGLContext->GetBufferBindingPointCount(target); + // Only sync up to the high-water mark of app-touched points; the fixed array is 36 + // deep but apps bind a handful, so the never-touched tail is already at GL default 0. + auto bindingPointCnt = MG_State::pGLContext->GetTouchedBufferBindingPointCount(target); for (SizeT i = 0; i < bindingPointCnt; ++i) { auto& point = MG_State::pGLContext->GetBufferBindingPoint(target, i); auto& obj = point.GetBoundObject(); diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp index efcffa76..a52e011c 100644 --- a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp @@ -1310,6 +1310,7 @@ namespace MobileGL::MG_Impl::GLImpl { BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return; if (!BufferImpl::ValidateBufferBindingPointIndex(bufferTarget, pointIndex)) return; + MG_State::pGLContext->TouchBufferBindingPoint(bufferTarget, pointIndex); auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, pointIndex); SharedPtr bufferObject; @@ -1342,6 +1343,7 @@ namespace MobileGL::MG_Impl::GLImpl { BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return; if (!BufferImpl::ValidateBufferBindingPointIndex(bufferTarget, index)) return; + MG_State::pGLContext->TouchBufferBindingPoint(bufferTarget, index); auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, index); SharedPtr bufferObject; diff --git a/MobileGL/MG_State/GLState/BufferState/BufferState.cpp b/MobileGL/MG_State/GLState/BufferState/BufferState.cpp index 1b3fec1e..b9217f23 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferState.cpp +++ b/MobileGL/MG_State/GLState/BufferState/BufferState.cpp @@ -13,6 +13,9 @@ namespace MobileGL::MG_State::GLState { for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { m_bindingSlots[i] = BindingSlot(GlobalBufferTargets[i]); } + for (SizeT i = 0; i < m_touchedBindPointCount.size(); ++i) { + m_touchedBindPointCount[i] = 0; + } } const SharedPtr& BufferState::GetBufferObject(Uint index) { diff --git a/MobileGL/MG_State/GLState/BufferState/BufferState.h b/MobileGL/MG_State/GLState/BufferState/BufferState.h index 3a6cba42..0fa94d68 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferState.h +++ b/MobileGL/MG_State/GLState/BufferState/BufferState.h @@ -36,6 +36,20 @@ namespace MobileGL::MG_State::GLState { auto index = std::distance(BufferBindPointTargets.begin(), it); return m_bufferBindPointTargets[index].size(); } + // High-water mark of app-touched binding points per target (highest index + 1, 0 if none). + // Lets the backend skip syncing the never-touched tail of the fixed 36-point array each draw. + void TouchBindPoint(const BufferTarget target, Uint index) { + auto it = std::find(BufferBindPointTargets.begin(), BufferBindPointTargets.end(), target); + if (it == BufferBindPointTargets.end()) return; + auto slot = std::distance(BufferBindPointTargets.begin(), it); + if (static_cast(index) + 1 > m_touchedBindPointCount[slot]) + m_touchedBindPointCount[slot] = static_cast(index) + 1; + } + SizeT GetTouchedBindPointCount(const BufferTarget target) const { + auto it = std::find(BufferBindPointTargets.begin(), BufferBindPointTargets.end(), target); + if (it == BufferBindPointTargets.end()) return 0; + return m_touchedBindPointCount[std::distance(BufferBindPointTargets.begin(), it)]; + } void MarkBufferObjectForDeletion(Uint index); Bool ValidateName(Uint index) const; Bool ValidateBufferObject(Uint index) const; @@ -48,5 +62,6 @@ namespace MobileGL::MG_State::GLState { // For glBindBufferBase / glBindBufferRange Array, BufferBindingPointCount>, BufferBindPointTargets.size()> m_bufferBindPointTargets; + Array m_touchedBindPointCount; }; } // namespace MobileGL::MG_State::GLState diff --git a/MobileGL/MG_State/GLState/Core.h b/MobileGL/MG_State/GLState/Core.h index c54733c5..ae472162 100644 --- a/MobileGL/MG_State/GLState/Core.h +++ b/MobileGL/MG_State/GLState/Core.h @@ -67,6 +67,12 @@ namespace MobileGL { constexpr SizeT GetBufferBindingPointCount(BufferTarget target) const { return m_bufferState.GetBindingPointCount(target); } + void TouchBufferBindingPoint(BufferTarget target, Uint index) { + m_bufferState.TouchBindPoint(target, index); + } + SizeT GetTouchedBufferBindingPointCount(BufferTarget target) const { + return m_bufferState.GetTouchedBindPointCount(target); + } const SharedPtr& CreateBufferObject(Uint index); void MarkBufferObjectForDeletion(Uint index); Bool ValidateBufferName(Uint index) const;