From 8532b2c45d2f4332a9ac9734b85c2ea2253cb8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Wed, 25 Mar 2026 21:36:02 -0700 Subject: [PATCH] Fix race between bgfx::begin and bgfx::frame encoder allocation. (#3646) * Fix race between bgfx::begin and bgfx::frame encoder allocation. * Update src/bgfx.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/bgfx.cpp | 15 +++++++++++---- src/bgfx_p.h | 5 +---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/bgfx.cpp b/src/bgfx.cpp index 66f312269..8280460a8 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -2405,7 +2405,8 @@ namespace bgfx if (_forceNewEncoder || BGFX_API_THREAD_MAGIC != s_threadIndex) { - bx::MutexScope scopeLock(m_encoderApiLock); + bx::MutexScope beginLockScope(m_encoderBeginLock); + bx::MutexScope encoderApiScope(m_encoderApiLock); uint16_t idx = m_encoderHandle->alloc(); if (kInvalidHandle == idx) @@ -2442,14 +2443,20 @@ namespace bgfx m_encoder[0].end(true); #if BGFX_CONFIG_MULTITHREADED - bx::MutexScope resourceApiScope(m_resourceApiLock); - - encoderApiWait(); + m_encoderBeginLock.lock(); // don't let any bgfx::begin calls... + encoderApiWait(); // wait for all started encoders to return... bx::MutexScope encoderApiScope(m_encoderApiLock); + m_encoderBeginLock.unlock(); + + bx::MutexScope resourceApiScope(m_resourceApiLock); #else encoderApiWait(); #endif // BGFX_CONFIG_MULTITHREADED + m_encoderHandle->reset(); + const uint16_t idx = m_encoderHandle->alloc(); + BX_ASSERT(0 == idx, "Internal encoder handle is not 0 (idx %d).", idx); BX_UNUSED(idx); + if (0 != (_flags & BGFX_FRAME_DISCARD) ) { m_submit->m_numRenderItems = 0; diff --git a/src/bgfx_p.h b/src/bgfx_p.h index e2d816964..d0deec1f8 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -5921,16 +5921,13 @@ namespace bgfx } m_submit->m_perfStats.numEncoders = uint8_t(numEncoders); - - m_encoderHandle->reset(); - uint16_t idx = m_encoderHandle->alloc(); - BX_ASSERT(0 == idx, "Internal encoder handle is not 0 (idx %d).", idx); BX_UNUSED(idx); } bx::Semaphore m_renderSem; bx::Semaphore m_apiSem; bx::Semaphore m_encoderEndSem; bx::Mutex m_encoderApiLock; + bx::Mutex m_encoderBeginLock; bx::Mutex m_resourceApiLock; bx::Thread m_thread; #else