From 7c6a7e5f008519f8234240dee104e34fdf9fe95e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Sun, 12 Jul 2026 20:30:42 -0700 Subject: [PATCH] D3D11/VK/Metal/GL: Fixed dangling framebuffer handle on destroy. (#3827) --- src/renderer_d3d11.cpp | 5 +++++ src/renderer_d3d12.cpp | 13 ++++++++++++ src/renderer_gl.cpp | 5 +++++ src/renderer_mtl.cpp | 5 +++++ src/renderer_vk.cpp | 47 ++++++++++++++++++++++++++++++++++-------- 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 8c00457cf..6de58f19c 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -2009,6 +2009,11 @@ namespace bgfx { namespace d3d11 void destroyFrameBuffer(FrameBufferHandle _handle) override { + if (m_fbh.idx == _handle.idx) + { + m_fbh = BGFX_INVALID_HANDLE; + } + uint16_t denseIdx = m_frameBuffers[_handle.idx].destroy(); if (UINT16_MAX != denseIdx) { diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index 109e13bc1..be762644d 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -748,6 +748,8 @@ namespace bgfx { namespace d3d12 , m_featureLevel(D3D_FEATURE_LEVEL(0) ) , m_swapChain(NULL) , m_backBufferDepthStencil(NULL) + , m_currentColor(NULL) + , m_currentDepthStencil(NULL) , m_wireframe(false) , m_lost(false) , m_maxAnisotropy(1) @@ -2378,6 +2380,11 @@ namespace bgfx { namespace d3d12 finishAll(true); } + if (m_fbh.idx == _handle.idx) + { + m_fbh = BGFX_INVALID_HANDLE; + } + uint16_t denseIdx = frameBuffer.destroy(); if (UINT16_MAX != denseIdx) { @@ -3103,6 +3110,11 @@ namespace bgfx { namespace d3d12 m_commandList->OMSetRenderTargets(1, m_currentColor, true, m_currentDepthStencil); } + else + { + m_currentColor = NULL; + m_currentDepthStencil = NULL; + } } else { @@ -6774,6 +6786,7 @@ namespace bgfx { namespace d3d12 m_nwh = NULL; m_numTh = 0; + m_num = 0; m_needPresent = false; m_depth.idx = bgfx::kInvalidHandle; diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index a6c045d2d..d6b572e57 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -3633,6 +3633,11 @@ namespace bgfx { namespace gl void destroyFrameBuffer(FrameBufferHandle _handle) override { + if (m_fbh.idx == _handle.idx) + { + m_fbh = BGFX_INVALID_HANDLE; + } + uint16_t denseIdx = m_frameBuffers[_handle.idx].destroy(); if (UINT16_MAX != denseIdx) { diff --git a/src/renderer_mtl.cpp b/src/renderer_mtl.cpp index 61f082ead..7e2290968 100644 --- a/src/renderer_mtl.cpp +++ b/src/renderer_mtl.cpp @@ -1455,6 +1455,11 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames void destroyFrameBuffer(FrameBufferHandle _handle) override { + if (m_fbh.idx == _handle.idx) + { + m_fbh = BGFX_INVALID_HANDLE; + } + uint16_t denseIdx = m_frameBuffers[_handle.idx].destroy(); if (UINT16_MAX != denseIdx) diff --git a/src/renderer_vk.cpp b/src/renderer_vk.cpp index 464ba6d26..359e5ed12 100644 --- a/src/renderer_vk.cpp +++ b/src/renderer_vk.cpp @@ -489,6 +489,27 @@ VK_IMPORT_DEVICE return supported; } + static bool wsiSurfaceSupported() + { +#if BX_PLATFORM_WINDOWS + return s_extension[Extension::KHR_win32_surface].m_supported; +#elif BX_PLATFORM_ANDROID + return s_extension[Extension::KHR_android_surface].m_supported; +#elif BX_PLATFORM_LINUX + return false + || s_extension[Extension::KHR_wayland_surface].m_supported + || s_extension[Extension::KHR_xlib_surface ].m_supported + || s_extension[Extension::KHR_xcb_surface ].m_supported + ; +#elif BX_PLATFORM_OSX + return s_extension[Extension::MVK_macos_surface].m_supported; +#elif BX_PLATFORM_NX + return s_extension[Extension::NN_vi_surface].m_supported; +#else + return false; +#endif // BX_PLATFORM_* + } + static const VkFormat s_attribType[][4][2] = { { // Int8 @@ -1336,7 +1357,8 @@ VK_IMPORT uint32_t numEnabledExtensions = 0; const char* enabledExtension[Extension::Count + 1]; - if (!headless) + if (!headless + || wsiSurfaceSupported() ) { enabledExtension[numEnabledExtensions++] = VK_KHR_SURFACE_EXTENSION_NAME; } @@ -1774,7 +1796,7 @@ VK_IMPORT_INSTANCE | (m_deviceFeatures.fullDrawIndexUint32 ? BGFX_CAPS_INDEX32 : 0) | BGFX_CAPS_INSTANCING | BGFX_CAPS_OCCLUSION_QUERY - | (!headless ? BGFX_CAPS_SWAP_CHAIN : 0) + | ( (!headless || wsiSurfaceSupported() ) ? BGFX_CAPS_SWAP_CHAIN : 0) | BGFX_CAPS_TEXTURE_2D_ARRAY | BGFX_CAPS_TEXTURE_3D | BGFX_CAPS_TEXTURE_BLIT @@ -1991,7 +2013,8 @@ VK_IMPORT_INSTANCE enabledExtension[numEnabledExtensions++] = VK_KHR_MAINTENANCE1_EXTENSION_NAME; - if (!headless) + if (!headless + || wsiSurfaceSupported() ) { enabledExtension[numEnabledExtensions++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME; } @@ -2675,6 +2698,11 @@ VK_IMPORT_DEVICE { FrameBufferVK& frameBuffer = m_frameBuffers[_handle.idx]; + if (m_fbh.idx == _handle.idx) + { + m_fbh = BGFX_INVALID_HANDLE; + } + uint16_t denseIdx = frameBuffer.destroy(); if (UINT16_MAX != denseIdx) { @@ -3154,12 +3182,6 @@ VK_IMPORT_DEVICE { BGFX_PROFILER_SCOPE("RendererContextVK::setFrameBuffer()", kColorFrame); - BX_ASSERT(false - || isValid(_fbh) - || NULL != m_backBuffer.m_nwh - , "Rendering to backbuffer in headless mode." - ); - FrameBufferVK& newFrameBuffer = isValid(_fbh) ? m_frameBuffers[_fbh.idx] : m_backBuffer @@ -3197,6 +3219,13 @@ VK_IMPORT_DEVICE } } + if (!isValid(_fbh) + && NULL == m_backBuffer.m_nwh) + { + m_fbh = _fbh; + return; + } + if (NULL == newFrameBuffer.m_nwh) { for (uint8_t ii = 0, num = newFrameBuffer.m_num; ii < num; ++ii)