From 997b0cfe36627f3960e148f55e473d3d4e74b80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Wed, 30 Sep 2026 12:06:59 -0700 Subject: [PATCH] Fixed MRT clear with UINT8_MAX palette index clearing the attachment on clear quad. (#4006) --- bindings/bf/bgfx.bf | 3 ++- bindings/c3/bgfx.c3 | 3 ++- bindings/cs/bgfx.cs | 3 ++- bindings/d/package.d | 3 ++- bindings/py/bgfx.pyi | 3 ++- bindings/zig/bgfx.zig | 3 ++- include/bgfx/bgfx.h | 3 ++- include/bgfx/c99/bgfx.h | 3 ++- scripts/bgfx.idl | 3 ++- src/bgfx.cpp | 21 +++++++++++++++++++++ src/bgfx_p.h | 17 +++++++++++++++++ src/renderer_d3d11.cpp | 24 +++++++++++++++++++----- src/renderer_d3d12.cpp | 2 +- src/renderer_gl.cpp | 35 +++++++++++++++++++++++++++++++++-- src/renderer_mtl.cpp | 25 +++++++++++++++++++++++-- src/renderer_vk.cpp | 30 ++++++++++++++++++++++++------ src/renderer_webgpu.cpp | 24 ++++++++++++++++++++---- 17 files changed, 176 insertions(+), 29 deletions(-) diff --git a/bindings/bf/bgfx.bf b/bindings/bf/bgfx.bf index 8e9c725c8..e8eb860c2 100644 --- a/bindings/bf/bgfx.bf +++ b/bindings/bf/bgfx.bf @@ -4423,7 +4423,8 @@ public static class bgfx /// /// Set view clear flags with different clear color for each /// frame buffer texture. `bgfx::setPaletteColor` must be used to set up a - /// clear color palette. + /// clear color palette. Frame buffer attachment with palette index set to + /// `UINT8_MAX` is not cleared. /// /// /// View id. diff --git a/bindings/c3/bgfx.c3 b/bindings/c3/bgfx.c3 index 00fe21ba2..f1ce29729 100644 --- a/bindings/c3/bgfx.c3 +++ b/bindings/c3/bgfx.c3 @@ -3230,7 +3230,8 @@ extern fn void set_view_clear(ushort _id, ushort _flags, uint _rgba, float _dept // Set view clear flags with different clear color for each // frame buffer texture. `bgfx::setPaletteColor` must be used to set up a -// clear color palette. +// clear color palette. Frame buffer attachment with palette index set to +// `UINT8_MAX` is not cleared. // _id : `View id.` // _flags : `Clear flags. Use `BGFX_CLEAR_NONE` to remove any clear operation. See: `BGFX_CLEAR_*`.` // _depth : `Depth clear value.` diff --git a/bindings/cs/bgfx.cs b/bindings/cs/bgfx.cs index 4773f01fc..d0e3b751d 100644 --- a/bindings/cs/bgfx.cs +++ b/bindings/cs/bgfx.cs @@ -4370,7 +4370,8 @@ public static partial class bgfx /// /// Set view clear flags with different clear color for each /// frame buffer texture. `bgfx::setPaletteColor` must be used to set up a - /// clear color palette. + /// clear color palette. Frame buffer attachment with palette index set to + /// `UINT8_MAX` is not cleared. /// /// /// View id. diff --git a/bindings/d/package.d b/bindings/d/package.d index 5d3d4eb43..328493016 100644 --- a/bindings/d/package.d +++ b/bindings/d/package.d @@ -3764,7 +3764,8 @@ mixin(joinFnBinds((){ /** * Set view clear flags with different clear color for each * frame buffer texture. `bgfx::setPaletteColor` must be used to set up a - * clear color palette. + * clear color palette. Frame buffer attachment with palette index set to + * `UINT8_MAX` is not cleared. Params: id = View id. flags = Clear flags. Use `BGFX_CLEAR_NONE` to remove any clear diff --git a/bindings/py/bgfx.pyi b/bindings/py/bgfx.pyi index 662348e28..bcb7bbb60 100644 --- a/bindings/py/bgfx.pyi +++ b/bindings/py/bgfx.pyi @@ -2613,7 +2613,8 @@ def bgfx_set_view_clear(_id: int, _flags: int, _rgba: int, _depth: float, _stenc # Set view clear flags with different clear color for each # frame buffer texture. `bgfx::setPaletteColor` must be used to set up a -# clear color palette. +# clear color palette. Frame buffer attachment with palette index set to +# `UINT8_MAX` is not cleared. def bgfx_set_view_clear_mrt( _id: int, _flags: int, diff --git a/bindings/zig/bgfx.zig b/bindings/zig/bgfx.zig index d95d2fcff..0f1df0bfd 100644 --- a/bindings/zig/bgfx.zig +++ b/bindings/zig/bgfx.zig @@ -3627,7 +3627,8 @@ extern fn bgfx_set_view_clear(_id: ViewId, _flags: u16, _rgba: u32, _depth: f32, /// Set view clear flags with different clear color for each /// frame buffer texture. `bgfx::setPaletteColor` must be used to set up a -/// clear color palette. +/// clear color palette. Frame buffer attachment with palette index set to +/// `UINT8_MAX` is not cleared. /// View id. /// Clear flags. Use `BGFX_CLEAR_NONE` to remove any clear operation. See: `BGFX_CLEAR_*`. /// Depth clear value. diff --git a/include/bgfx/bgfx.h b/include/bgfx/bgfx.h index 59ad1bfe8..dd12739b8 100644 --- a/include/bgfx/bgfx.h +++ b/include/bgfx/bgfx.h @@ -4202,7 +4202,8 @@ namespace bgfx /// Set view clear flags with different clear color for each /// frame buffer texture. `bgfx::setPaletteColor` must be used to set up a - /// clear color palette. + /// clear color palette. Frame buffer attachment with palette index set to + /// `UINT8_MAX` is not cleared. /// /// @param[in] _id View id. /// @param[in] _flags Clear flags. Use `BGFX_CLEAR_NONE` to remove any clear diff --git a/include/bgfx/c99/bgfx.h b/include/bgfx/c99/bgfx.h index ba01a3bd9..be7f818d9 100644 --- a/include/bgfx/c99/bgfx.h +++ b/include/bgfx/c99/bgfx.h @@ -2928,7 +2928,8 @@ BGFX_C_API void bgfx_set_view_clear(bgfx_view_id_t _id, uint16_t _flags, uint32_ /** * Set view clear flags with different clear color for each * frame buffer texture. `bgfx::setPaletteColor` must be used to set up a - * clear color palette. + * clear color palette. Frame buffer attachment with palette index set to + * `UINT8_MAX` is not cleared. * * @param[in] _id View id. * @param[in] _flags Clear flags. Use `BGFX_CLEAR_NONE` to remove any clear diff --git a/scripts/bgfx.idl b/scripts/bgfx.idl index 1e4d5d531..6ed1a4f62 100644 --- a/scripts/bgfx.idl +++ b/scripts/bgfx.idl @@ -2557,7 +2557,8 @@ func.setViewClear { section = "Views" } --- Set view clear flags with different clear color for each --- frame buffer texture. `bgfx::setPaletteColor` must be used to set up a ---- clear color palette. +--- clear color palette. Frame buffer attachment with palette index set to +--- `UINT8_MAX` is not cleared. func.setViewClear { cname = "set_view_clear_mrt", section = "Views" } "void" .id "ViewId" --- View id. diff --git a/src/bgfx.cpp b/src/bgfx.cpp index 1545fc8c5..b90f36151 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -6209,6 +6209,7 @@ namespace bgfx , storageSize , _mem->size ); + BX_UNUSED(storageSize); } uint32_t size = sizeof(uint32_t)+sizeof(TextureCreate); @@ -6281,6 +6282,7 @@ namespace bgfx , storageSize , _mem->size ); + BX_UNUSED(storageSize); } uint32_t size = sizeof(uint32_t)+sizeof(TextureCreate); @@ -6332,6 +6334,7 @@ namespace bgfx , storageSize , _mem->size ); + BX_UNUSED(storageSize); } uint32_t size = sizeof(uint32_t)+sizeof(TextureCreate); @@ -6701,6 +6704,24 @@ namespace bgfx void setViewClear(ViewId _id, uint16_t _flags, float _depth, uint8_t _stencil, uint8_t _0, uint8_t _1, uint8_t _2, uint8_t _3, uint8_t _4, uint8_t _5, uint8_t _6, uint8_t _7) { BX_ASSERT(checkView(_id), "Invalid view id: %d", _id); + + if (BX_ENABLED(BGFX_CONFIG_DEBUG) ) + { + const uint8_t index[] = { _0, _1, _2, _3, _4, _5, _6, _7 }; + + for (uint32_t ii = 0; ii < BX_COUNTOF(index); ++ii) + { + BX_ASSERT(UINT8_MAX == index[ii] || index[ii] < BGFX_CONFIG_MAX_COLOR_PALETTE + , "setViewClear: Invalid palette index %d for frame buffer attachment %d (must be less than BGFX_CONFIG_MAX_COLOR_PALETTE (%d), or UINT8_MAX to leave the attachment unchanged)." + , index[ii] + , ii + , BGFX_CONFIG_MAX_COLOR_PALETTE + ); + } + + BX_UNUSED(index); + } + s_ctx->setViewClear(_id, _flags, _depth, _stencil, _0, _1, _2, _3, _4, _5, _6, _7); } diff --git a/src/bgfx_p.h b/src/bgfx_p.h index 2656d34bf..e00913827 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -549,6 +549,23 @@ namespace bgfx m_stencil = _stencil; } + uint8_t getColorSkipMask(uint32_t _num) const + { + if (0 == (m_flags & BGFX_CLEAR_COLOR_USE_PALETTE) ) + { + return 0; + } + + uint8_t mask = 0; + + for (uint32_t ii = 0, num = bx::min(_num, BX_COUNTOF(m_index) ); ii < num; ++ii) + { + mask |= UINT8_MAX == m_index[ii] ? 1<CreateBlendState(&desc, &bs) ); m_blendStateCache.add(hash, bs); @@ -3854,10 +3868,6 @@ namespace bgfx { namespace d3d11 : 0 ; - setBlendState(state); - setDepthStencilState(state, stencil); - setRasterizerState(state); - uint32_t numMrt = 1; FrameBufferHandle fbh = m_fbh; if (isValid(fbh) ) @@ -3866,6 +3876,10 @@ namespace bgfx { namespace d3d11 numMrt = bx::max(1, fb.m_num); } + setBlendState(state, 0, UINT32_MAX, uint8_t(~_clear.getColorSkipMask(numMrt) ) ); + setDepthStencilState(state, stencil); + setRasterizerState(state); + ProgramD3D11& program = m_program[_clearQuad.m_program[numMrt-1].idx]; m_currentProgram = &program; diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index 61de705df..ee3079b9c 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -2128,7 +2128,7 @@ namespace bgfx { namespace d3d12 void shutdown() { - m_cmd.finish(); + finishAll(true); m_batch.destroy(); DX_RELEASE(m_zeroInitBuffer, 0); diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index f4567435c..5773eeb79 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -4876,8 +4876,13 @@ namespace bgfx { namespace gl GLint intClear[4] = {}; + const bool clearColor = true + && 0 != (BGFX_CLEAR_COLOR & _clear.m_flags) + && 0 == _clear.getColorSkipMask(1) + ; + GLuint flags = 0; - if (BGFX_CLEAR_COLOR & _clear.m_flags) + if (clearColor) { if (BGFX_CLEAR_COLOR_USE_PALETTE & _clear.m_flags) { @@ -4941,7 +4946,7 @@ namespace bgfx { namespace gl GL_CHECK(glStencilMask(0xff) ); } - const bool clearColorInt = intColor && 0 != (BGFX_CLEAR_COLOR & _clear.m_flags); + const bool clearColorInt = intColor && clearColor; if (0 != flags || clearColorInt) @@ -5081,10 +5086,36 @@ namespace bgfx { namespace gl commit(*program.m_constantBuffer); + const uint8_t skipMask = _clear.getColorSkipMask(numMrt); + GLenum buffers[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS]; + + if (0 != skipMask) + { + for (uint32_t ii = 0; ii < numMrt; ++ii) + { + buffers[ii] = 0 != (skipMask & (1<m_rps); @@ -2971,6 +2973,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames , ProgramHandle _program , uint8_t _numInstanceData , uint32_t _sampleMask = UINT32_MAX + , uint8_t _mrtMask = UINT8_MAX ) { _state &= (0 @@ -2994,7 +2997,8 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames && m_lastPsoState.m_fbh == _fbh.idx && m_lastPsoState.m_numStreams == _numStreams && m_lastPsoState.m_numInstanceData == _numInstanceData - && m_lastPsoState.m_sampleMask == _sampleMask) + && m_lastPsoState.m_sampleMask == _sampleMask + && m_lastPsoState.m_mrtMask == _mrtMask) { bool match = true; for (uint8_t ii = 0; ii < _numStreams && match; ++ii) @@ -3015,6 +3019,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames m_lastPsoState.m_numStreams = _numStreams; m_lastPsoState.m_numInstanceData = _numInstanceData; m_lastPsoState.m_sampleMask = _sampleMask; + m_lastPsoState.m_mrtMask = _mrtMask; for (uint8_t ii = 0; ii < _numStreams; ++ii) { m_lastPsoState.m_layouts[ii] = _layouts[ii]; @@ -3028,6 +3033,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames murmur.add(rgba); murmur.add(_numInstanceData); murmur.add(_sampleMask); + murmur.add(_mrtMask); if (!isValid(_fbh) ) { @@ -3193,6 +3199,17 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames } } + if (UINT8_MAX != _mrtMask) + { + for (uint32_t ii = 0; ii < frameBufferAttachment; ++ii) + { + if (0 == (_mrtMask & (1<colorAttachments()->object(ii)->setWriteMask(MTL::ColorWriteMaskNone); + } + } + } + pd->setVertexFunction(program.m_vsh->m_function); pd->setFragmentFunction(program.m_fsh != NULL ? program.m_fsh->getFunction(_sampleMask) @@ -3688,6 +3705,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames uint16_t m_fbh; uint8_t m_numStreams; uint8_t m_numInstanceData; + uint8_t m_mrtMask; }; PipelineState m_lastPsoState; @@ -6289,13 +6307,16 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames if (clearWithRenderPass) { + const uint8_t colorSkipMask = clr.getColorSkipMask(g_caps.limits.maxFBAttachments); + for (uint32_t ii = 0; ii < g_caps.limits.maxFBAttachments; ++ii) { MTL::RenderPassColorAttachmentDescriptor* desc = renderPassDescriptor->colorAttachments()->object(ii); if (desc->texture() != NULL) { - if (0 != (BGFX_CLEAR_COLOR & clr.m_flags) ) + if (0 != (BGFX_CLEAR_COLOR & clr.m_flags) + && 0 == (colorSkipMask & (1<m_view[view].m_clear.m_flags); + const Clear& clr = _render->m_view[view].m_clear; + + const bool partialColorClear = true + && 0 != (clr.m_flags & BGFX_CLEAR_COLOR) + && 0 != clr.getColorSkipMask(NULL == fb.m_nwh ? fb.m_num : 1) + ; + + VkRenderPass renderPass = fb.getRenderPass(partialColorClear + ? clr.m_flags & ~BGFX_CLEAR_COLOR + : clr.m_flags + ); viewState.m_rect = _render->m_view[view].m_rect; const Rect& rect = _render->m_view[view].m_rect; @@ -10671,8 +10685,6 @@ VK_DESTROY VkClearValue clearValues[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS + 1]; uint32_t mrt = 0; - const Clear& clr = _render->m_view[view].m_clear; - for (uint32_t ii = 0; ii < numMrt; ++ii) { if (BGFX_CLEAR_COLOR & clr.m_flags) @@ -10738,10 +10750,16 @@ VK_DESTROY vkCmdBeginRenderPass(m_commandBuffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE); beginRenderPass = true; + + if (partialColorClear) + { + Clear colorClr = clr; + colorClr.m_flags &= ~(BGFX_CLEAR_DEPTH|BGFX_CLEAR_STENCIL); + clearQuad(renderArea, colorClr, _render->m_colorPalette); + } } else { - const Clear& clr = _render->m_view[view].m_clear; if (BGFX_CLEAR_NONE != clr.m_flags) { Rect clearRect; diff --git a/src/renderer_webgpu.cpp b/src/renderer_webgpu.cpp index 046a4b5cb..cc1b76f95 100644 --- a/src/renderer_webgpu.cpp +++ b/src/renderer_webgpu.cpp @@ -2567,6 +2567,12 @@ WGPU_IMPORT , true , renderBind , true + , false + , 0 + , 0.0f + , 0.0f + , UINT32_MAX + , uint8_t(~_clear.getColorSkipMask(numMrt) ) ); const ProgramWGPU& program = m_program[_clearQuad.m_program[numMrt-1].idx]; @@ -3206,6 +3212,7 @@ WGPU_IMPORT , float _slopeScale = 0.0f , float _biasClamp = 0.0f , uint32_t _sampleMask = UINT32_MAX + , uint8_t _mrtMask = UINT8_MAX ) { const ProgramWGPU& program = m_program[_program.idx]; @@ -3310,6 +3317,7 @@ WGPU_IMPORT murmur.add(_slopeScale); murmur.add(_biasClamp); murmur.add(_sampleMask); + murmur.add(_mrtMask); const uint32_t hash = murmur.end(); RenderPipeline* renderPipeline = m_renderPipelineCache.find(hash); @@ -3458,7 +3466,7 @@ WGPU_IMPORT const bool hasFragmentShader = NULL != program.m_fsh; const bool bgra8Storage = hasBgra8Storage(entries, entryCount); - const uint32_t targetCount = hasFragmentShader ? setColorTargetState(blendState, colorTragetState, fb, _state, _rgba) : 0; + const uint32_t targetCount = hasFragmentShader ? setColorTargetState(blendState, colorTragetState, fb, _state, _rgba, _mrtMask) : 0; if (NULL != depthStencilTextureView) { @@ -3707,7 +3715,7 @@ WGPU_IMPORT } } - uint32_t setColorTargetState(WGPUBlendState* _outBlendState, WGPUColorTargetState* _outColorTargetState, const FrameBufferWGPU& _fb, uint64_t _state, uint32_t _rgba = 0) + uint32_t setColorTargetState(WGPUBlendState* _outBlendState, WGPUColorTargetState* _outColorTargetState, const FrameBufferWGPU& _fb, uint64_t _state, uint32_t _rgba = 0, uint8_t _mrtMask = UINT8_MAX) { if (0 == _fb.m_numColorAttachments && !_fb.isSwapChain() ) @@ -3807,7 +3815,10 @@ WGPU_IMPORT .nextInChain = NULL, .format = format, .blend = blend, - .writeMask = writeMask, + .writeMask = 0 != (_mrtMask & (1<