From 5a2eec324698ff203edbac522bfb2da392f73adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Wed, 2 Sep 2026 08:46:26 -0700 Subject: [PATCH] Fixed matrix cache growth strategy. Fixes #3952. --- src/bgfx_p.h | 186 +++++++++++++++++++++++++++++++++++-------------- src/renderer.h | 8 +-- 2 files changed, 137 insertions(+), 57 deletions(-) diff --git a/src/bgfx_p.h b/src/bgfx_p.h index b5a90798e..b661a34c3 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -1803,16 +1803,21 @@ namespace bgfx struct MatrixCache { + static constexpr uint32_t kMaxChunks = 16; + MatrixCache() - : m_cache(NULL) - , m_num(1) + : m_num(1) , m_max(0) , m_capacity(0) + , m_numChunks(0) , m_peak(0) , m_observe(0) , m_numPeakFrames(0) - , m_overflowedBy(0) { + bx::memSet(m_chunk, 0, sizeof(m_chunk) ); + bx::memSet(m_chunkBase, 0, sizeof(m_chunkBase) ); + bx::memSet(m_chunkSize, 0, sizeof(m_chunkSize) ); + m_identity.setIdentity(); } void create(uint32_t _numReserved, uint32_t _numMax, uint32_t _numPeakFrames) @@ -1825,26 +1830,91 @@ namespace bgfx _numPeakFrames = 0; } - m_max = bx::min(_numReserved, m_capacity); - alloc(); - m_num = 1; - m_peak = 0; - m_observe = 0; + resize(bx::min(_numReserved, m_capacity) ); + + m_num = 1; + m_peak = 0; + m_observe = 0; m_numPeakFrames = _numPeakFrames; - m_overflowedBy = 0; } void destroy() { - bx::free(g_allocator, m_cache); - m_cache = NULL; + freeChunks(); + } + + void freeChunks() + { + for (uint32_t ii = 0; ii < m_numChunks; ++ii) + { + bx::free(g_allocator, m_chunk[ii], BX_ALIGNOF(Matrix4) ); + m_chunk[ii] = NULL; + } + + m_numChunks = 0; + m_max = 0; } void resize(uint32_t _max) { - bx::free(g_allocator, m_cache); - m_max = _max; - alloc(); + freeChunks(); + addChunk(_max); + } + + bool addChunk(uint32_t _num) + { + if (m_numChunks == kMaxChunks + || m_max >= m_capacity) + { + return false; + } + + const uint32_t size = bx::min( + m_capacity - m_max + , bx::max(_num, bx::max(kDrawCallBlock, m_max) ) + ); + + Matrix4* chunk = (Matrix4*)bx::alloc(g_allocator, sizeof(Matrix4)*size, BX_ALIGNOF(Matrix4) ); + + if (0 == m_numChunks) + { + chunk[0].setIdentity(); + } + + m_chunkBase[m_numChunks] = m_max; + m_chunkSize[m_numChunks] = size; + m_chunk[m_numChunks] = chunk; + + bx::atomicFetchAndAdd(&m_numChunks, 1); + bx::atomicFetchAndAdd(&m_max, size); + + return true; + } + + Matrix4& at(uint32_t _idx) + { + if (_idx < m_chunkSize[0]) + { + return m_chunk[0][_idx]; + } + + for (uint32_t ii = 1, num = m_numChunks; ii < num; ++ii) + { + const uint32_t base = m_chunkBase[ii]; + + if (_idx >= base + && _idx < base + m_chunkSize[ii]) + { + return m_chunk[ii][_idx - base]; + } + } + + return m_identity; + } + + const Matrix4& at(uint32_t _idx) const + { + return const_cast(this)->at(_idx); } uint32_t capacityFor(uint32_t _used) const @@ -1856,10 +1926,9 @@ namespace bgfx { const uint32_t used = m_num; - if (0 != m_overflowedBy - && m_max < m_capacity) + if (1 < m_numChunks) { - resize(bx::min(m_capacity, capacityFor(m_max + m_overflowedBy) ) ); + resize(bx::min(m_capacity, capacityFor(used) ) ); m_peak = 0; m_observe = 0; } @@ -1881,24 +1950,42 @@ namespace bgfx } } - m_overflowedBy = 0; - m_num = 1; + m_num = 1; } uint32_t reserve(uint16_t* _num) { - uint32_t num = *_num; - uint32_t first = bx::atomicFetchAndAddsat(&m_num, num, m_max); + const uint32_t num = *_num; - if (first+num > m_max) + for (;;) { - bx::atomicFetchAndAddsat(&m_overflowedBy, num, m_capacity); + const uint32_t max = m_max; + const uint32_t first = bx::atomicFetchAndAddsat(&m_num, num, max); + + if (first + num <= max) + { + *_num = bx::narrowCast(num); + return first; + } + + if (!grow(num, max) ) + { + *_num = 0; + return m_max; + } + } + } + + BX_NO_INLINE bool grow(uint32_t _num, uint32_t _max) + { + bx::MutexScope lock(m_lock); + + if (m_max != _max) + { + return true; } - num = bx::min(num, m_max-first); - *_num = bx::narrowCast(num); - - return first; + return addChunk(_num); } uint32_t add(const void* _mtx, uint16_t* _num) @@ -1906,7 +1993,12 @@ namespace bgfx if (NULL != _mtx) { uint32_t first = reserve(_num); - bx::memCopy(&m_cache[first], _mtx, sizeof(Matrix4)*(*_num) ); + + if (0 != *_num) + { + bx::memCopy(&at(first), _mtx, sizeof(Matrix4)*(*_num) ); + } + return first; } @@ -1917,33 +2009,21 @@ namespace bgfx float* toPtr(uint32_t _cacheIdx) { - BX_ASSERT(_cacheIdx <= m_max, "Matrix cache out of bounds index %d (max: %d)" - , _cacheIdx - , m_max - ); - return m_cache[_cacheIdx].un.val; + return at(_cacheIdx).un.val; } - uint32_t fromPtr(const void* _ptr) const - { - return uint32_t( (const Matrix4*)_ptr - m_cache); - } - - void alloc() - { - m_cache = (Matrix4*)bx::alloc(g_allocator, sizeof(Matrix4)*(m_max + 1) ); - m_cache[0].setIdentity(); - m_cache[m_max].setIdentity(); - } - - Matrix4* m_cache; - uint32_t m_num; - uint32_t m_max; - uint32_t m_capacity; - uint32_t m_peak; - uint32_t m_observe; - uint32_t m_numPeakFrames; - uint32_t m_overflowedBy; + Matrix4* m_chunk[kMaxChunks]; + uint32_t m_chunkBase[kMaxChunks]; + uint32_t m_chunkSize[kMaxChunks]; + Matrix4 m_identity; + uint32_t m_num; + uint32_t m_max; + uint32_t m_capacity; + uint32_t m_numChunks; + uint32_t m_peak; + uint32_t m_observe; + uint32_t m_numPeakFrames; + bx::Mutex m_lock; }; struct RectCache diff --git a/src/renderer.h b/src/renderer.h index a9783f71c..020e282ad 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -243,7 +243,7 @@ namespace bgfx case PredefinedUniform::Model: { - const Matrix4& model = frameCache.m_matrixCache.m_cache[_draw.m_startMatrix]; + const Matrix4& model = frameCache.m_matrixCache.at(_draw.m_startMatrix); _renderer->setShaderUniform4x4f(flags , predefined.m_loc , model.un.val @@ -255,7 +255,7 @@ namespace bgfx case PredefinedUniform::ModelView: { Matrix4 modelView; - const Matrix4& model = frameCache.m_matrixCache.m_cache[_draw.m_startMatrix]; + const Matrix4& model = frameCache.m_matrixCache.at(_draw.m_startMatrix); bx::model4x4_mul(&modelView.un.f4x4 , &model.un.f4x4 , &m_view[_view].un.f4x4 @@ -272,7 +272,7 @@ namespace bgfx { Matrix4 modelView; Matrix4 invModelView; - const Matrix4& model = frameCache.m_matrixCache.m_cache[_draw.m_startMatrix]; + const Matrix4& model = frameCache.m_matrixCache.at(_draw.m_startMatrix); bx::model4x4_mul(&modelView.un.f4x4 , &model.un.f4x4 , &m_view[_view].un.f4x4 @@ -291,7 +291,7 @@ namespace bgfx case PredefinedUniform::ModelViewProj: { Matrix4 modelViewProj; - const Matrix4& model = frameCache.m_matrixCache.m_cache[_draw.m_startMatrix]; + const Matrix4& model = frameCache.m_matrixCache.at(_draw.m_startMatrix); bx::model4x4_mul_viewproj4x4(&modelViewProj.un.f4x4 , &model.un.f4x4 , &m_viewProj[_view].un.f4x4