From 8f451e9102b1845b29dfe500116611ad283632ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Thu, 8 Oct 2026 21:47:03 -0700 Subject: [PATCH] VK: Fall back to supported surface format and composite alpha. Fixes #4032. (#4035) --- src/bgfx.cpp | 41 +++++++++++ src/renderer_d3d12.h | 4 ++ src/renderer_gl.cpp | 3 +- src/renderer_vk.cpp | 154 +++++++++++++++++++++++++++++++++++----- src/renderer_webgpu.cpp | 1 + 5 files changed, 186 insertions(+), 17 deletions(-) diff --git a/src/bgfx.cpp b/src/bgfx.cpp index dd16f962c..3641d0d58 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -2307,6 +2307,37 @@ namespace bgfx TextureFormat::RGBA8, // D3D9 doesn't support RGBA8 }; + static TextureFormat::Enum findBackBufferFormat(TextureFormat::Enum _format) + { + const TextureFormat::Enum preferred[] = + { + _format, + TextureFormat::BGRA8, + TextureFormat::RGBA8, + }; + + for (uint32_t ii = 0; ii < BX_COUNTOF(preferred); ++ii) + { + const TextureFormat::Enum format = preferred[ii]; + + if (TextureFormat::Count != format + && 0 != (g_caps.formats[format] & BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER) ) + { + return format; + } + } + + for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii) + { + if (0 != (g_caps.formats[ii] & BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER) ) + { + return TextureFormat::Enum(ii); + } + } + + return _format; + } + bool Context::init(const Init& _init) { if (m_rendererInitialized) @@ -2493,6 +2524,16 @@ namespace bgfx m_init.reset = checkResetFlags(m_init.reset); + const TextureFormat::Enum formatColor = findBackBufferFormat(m_init.swapChain.formatColor); + + BX_WARN(formatColor == m_init.swapChain.formatColor + , "Back buffer format %s is not supported, using %s instead." + , TextureFormat::Count == m_init.swapChain.formatColor ? "Count" : getName(m_init.swapChain.formatColor) + , getName(formatColor) + ); + + m_init.swapChain.formatColor = formatColor; + dumpCaps(); m_textVideoMemBlitter.init(); diff --git a/src/renderer_d3d12.h b/src/renderer_d3d12.h index e2a98b72e..bb585d492 100644 --- a/src/renderer_d3d12.h +++ b/src/renderer_d3d12.h @@ -42,7 +42,11 @@ extern "C" struct PIXEventsThreadInfo* WINAPI bgfx_PIXGetThreadInfo(); extern "C" uint64_t WINAPI bgfx_PIXEventsReplaceBlock(PIXEventsThreadInfo* _threadInfo, bool _getEarliestTime); # endif // BX_PLATFORM_WINDOWS +BX_PRAGMA_DIAGNOSTIC_PUSH(); +BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wundef"); +BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-but-set-variable"); # include +BX_PRAGMA_DIAGNOSTIC_POP(); # define _PIX3_BEGINEVENT(_commandList, _color, _name) PIXBeginEvent(_commandList, toPixColor(_color), _name) # define _PIX3_SETMARKER(_commandList, _color, _name) PIXSetMarker(_commandList, toPixColor(_color), _name) diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 6871ef59b..0e9038381 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -2786,7 +2786,8 @@ namespace bgfx { namespace gl g_caps.formats[ii] = supported; } - g_caps.formats[TextureFormat::BGRA8] |= BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER; + g_caps.formats[TextureFormat::BGRA8 ] |= BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER; + g_caps.formats[TextureFormat::RGB10A2] |= BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER; g_caps.supported |= BGFX_CAPS_VERTEX_ATTRIB_UINT10; g_caps.supported |= (false diff --git a/src/renderer_vk.cpp b/src/renderer_vk.cpp index a4b283014..cc741e6c0 100644 --- a/src/renderer_vk.cpp +++ b/src/renderer_vk.cpp @@ -3455,7 +3455,8 @@ VK_IMPORT_DEVICE release(m_captureBuffer); recycleMemory(m_captureMemory); - m_captureSize = 0; + m_captureMemory = {}; + m_captureSize = 0; } } @@ -3478,7 +3479,7 @@ VK_IMPORT_DEVICE VK_CHECK(createReadbackBuffer(m_captureSize, &m_captureBuffer, &m_captureMemory) ); } - g_callback->captureBegin(m_mainSwapChain.width, m_mainSwapChain.height, pitch, m_mainSwapChain.formatColor, false); + g_callback->captureBegin(m_mainSwapChain.width, m_mainSwapChain.height, pitch, m_backBuffer.m_swapChain.m_colorFormat, false); } } @@ -8926,7 +8927,7 @@ VK_DESTROY const VkColorSpaceKHR surfaceColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; const bool srgb = !!(m_desc.flags & BGFX_SWAP_CHAIN_SRGB_BACKBUFFER); - m_colorFormat = m_desc.formatColor; + m_colorFormat = findSurfaceFormat(m_desc.formatColor, surfaceColorSpace, srgb); m_depthFormat = bgfx::TextureFormat::UnknownDepth; if (TextureFormat::Count == m_colorFormat) @@ -8960,24 +8961,43 @@ VK_DESTROY ); } - VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - - if (m_desc.flags & BGFX_SWAP_CHAIN_TRANSPARENT_BACKBUFFER) + static const VkCompositeAlphaFlagBitsKHR s_compositeAlphaOpaque[] = { - if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + }; + + static const VkCompositeAlphaFlagBitsKHR s_compositeAlphaTransparent[] = + { + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + }; + + const VkCompositeAlphaFlagBitsKHR* compositeAlphaPreference = (m_desc.flags & BGFX_SWAP_CHAIN_TRANSPARENT_BACKBUFFER) + ? s_compositeAlphaTransparent + : s_compositeAlphaOpaque + ; + + VkCompositeAlphaFlagBitsKHR compositeAlpha = compositeAlphaPreference[0]; + + for (uint32_t ii = 0; ii < BX_COUNTOF(s_compositeAlphaOpaque); ++ii) + { + if (surfaceCapabilities.supportedCompositeAlpha & compositeAlphaPreference[ii]) { - compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - } - else if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) - { - compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; - } - else if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) - { - compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; + compositeAlpha = compositeAlphaPreference[ii]; + break; } } + BX_WARN(0 != (surfaceCapabilities.supportedCompositeAlpha & compositeAlpha) + , "Create swapchain: No supported composite alpha mode (supported: 0x%x)." + , surfaceCapabilities.supportedCompositeAlpha + ); + const VkImageUsageFlags imageUsageMask = 0 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT @@ -9449,6 +9469,108 @@ VK_DESTROY return idx; } + TextureFormat::Enum SwapChainVK::findSurfaceFormat(TextureFormat::Enum _format, VkColorSpaceKHR _colorSpace, bool _srgb) + { + BGFX_PROFILER_SCOPE("SwapChainVK::findSurfaceFormat", kColorFrame); + + const VkPhysicalDevice physicalDevice = s_renderVK->m_physicalDevice; + + uint32_t numSurfaceFormats; + VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_surface, &numSurfaceFormats, NULL); + + if (VK_SUCCESS != result + || 0 == numSurfaceFormats) + { + BX_TRACE("findSurfaceFormat error: vkGetPhysicalDeviceSurfaceFormatsKHR failed %d: %s.", result, getName(result) ); + return _format; + } + + VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)BX_STACK_ALLOC(numSurfaceFormats * sizeof(VkSurfaceFormatKHR) ); + result = vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_surface, &numSurfaceFormats, surfaceFormats); + + if (VK_SUCCESS != result) + { + BX_TRACE("findSurfaceFormat error: vkGetPhysicalDeviceSurfaceFormatsKHR failed %d: %s.", result, getName(result) ); + return _format; + } + + if (1 == numSurfaceFormats + && VK_FORMAT_UNDEFINED == surfaceFormats[0].format) + { + return _format; + } + + const TextureFormat::Enum preferredFormats[] = + { + _format, + TextureFormat::BGRA8, + TextureFormat::RGBA8, + }; + + for (uint32_t ii = 0; ii < BX_COUNTOF(preferredFormats); ++ii) + { + const TextureFormat::Enum format = preferredFormats[ii]; + + if (TextureFormat::Count == format) + { + continue; + } + + const VkFormat vkFormat = _srgb + ? s_textureFormat[format].m_fmtSrgb + : s_textureFormat[format].m_fmt + ; + + if (VK_FORMAT_UNDEFINED == vkFormat) + { + continue; + } + + for (uint32_t jj = 0; jj < numSurfaceFormats; ++jj) + { + if (_colorSpace == surfaceFormats[jj].colorSpace + && vkFormat == surfaceFormats[jj].format) + { + BX_WARN(format == _format + , "findSurfaceFormat: Surface format %s is not supported, using %s instead." + , TextureFormat::Count == _format ? "Count" : bimg::getName(bimg::TextureFormat::Enum(_format) ) + , bimg::getName(bimg::TextureFormat::Enum(format) ) + ); + return format; + } + } + } + + for (uint32_t jj = 0; jj < numSurfaceFormats; ++jj) + { + if (_colorSpace != surfaceFormats[jj].colorSpace) + { + continue; + } + + for (uint32_t ii = TextureFormat::Unknown+1; ii < TextureFormat::UnknownDepth; ++ii) + { + const VkFormat vkFormat = _srgb + ? s_textureFormat[ii].m_fmtSrgb + : s_textureFormat[ii].m_fmt + ; + + if (VK_FORMAT_UNDEFINED != vkFormat + && vkFormat == surfaceFormats[jj].format) + { + BX_TRACE("findSurfaceFormat: Surface format %s is not supported, using %s instead." + , TextureFormat::Count == _format ? "Count" : bimg::getName(bimg::TextureFormat::Enum(_format) ) + , bimg::getName(bimg::TextureFormat::Enum(ii) ) + ); + return TextureFormat::Enum(ii); + } + } + } + + BX_TRACE("findSurfaceFormat error: No supported surface format found."); + return TextureFormat::Count; + } + bool SwapChainVK::acquire(VkCommandBuffer _commandBuffer, bool _block) { BGFX_PROFILER_SCOPE("SwapChainVK::acquire", kColorFrame); diff --git a/src/renderer_webgpu.cpp b/src/renderer_webgpu.cpp index 59f472c86..ee8af8d63 100644 --- a/src/renderer_webgpu.cpp +++ b/src/renderer_webgpu.cpp @@ -1478,6 +1478,7 @@ WGPU_IMPORT } g_caps.formats[TextureFormat::BGRA8] |= BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER; + g_caps.formats[TextureFormat::RGBA8] |= BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER; } }