From 8e50cd586cb4b1826bd84332392ca86fb94e9e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Fri, 24 Jul 2026 15:44:05 -0700 Subject: [PATCH] Fixed auto-gen mips on resolved MSAA render targets. (#3845) --- src/renderer_d3d11.cpp | 7 +++- src/renderer_d3d11.h | 6 +-- src/renderer_d3d12.cpp | 81 ++++++++++++++++++++++++++++++----------- src/renderer_mtl.h | 4 +- src/renderer_vk.cpp | 83 +++++++++++++++++++++++++++++++++++++++++- 5 files changed, 152 insertions(+), 29 deletions(-) diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 8695acc4c..20b767d63 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -4849,7 +4849,12 @@ namespace bgfx { namespace d3d11 desc.MipLevels = 1; DX_CHECK(s_renderD3D11->m_device->CreateTexture2D(&desc, NULL, &m_rt2d) ); - desc.BindFlags &= ~(D3D11_BIND_RENDER_TARGET|D3D11_BIND_DEPTH_STENCIL); + const bool autoGenMips = 0 != (desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS); + desc.BindFlags &= ~D3D11_BIND_DEPTH_STENCIL; + if (!autoGenMips) + { + desc.BindFlags &= ~D3D11_BIND_RENDER_TARGET; + } desc.SampleDesc = s_msaa[0]; desc.MipLevels = savedMipLevels; } diff --git a/src/renderer_d3d11.h b/src/renderer_d3d11.h index db5b1f72c..d5ac5af0c 100644 --- a/src/renderer_d3d11.h +++ b/src/renderer_d3d11.h @@ -352,9 +352,9 @@ namespace bgfx { namespace d3d11 void set(); HRESULT present(uint32_t _syncInterval, uint32_t _flags); - ID3D11RenderTargetView* m_rtv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1]; - ID3D11UnorderedAccessView* m_uav[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1]; - ID3D11ShaderResourceView* m_srv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1]; + ID3D11RenderTargetView* m_rtv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS]; + ID3D11UnorderedAccessView* m_uav[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS]; + ID3D11ShaderResourceView* m_srv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS]; ID3D11DepthStencilView* m_dsv; Dxgi::SwapChainI* m_swapChain; void* m_nwh; diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index 0d6e64c1f..a644c2325 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -2749,10 +2749,10 @@ namespace bgfx { namespace d3d12 DX_RELEASE(m_backBufferColor[ii], 1); #endif // BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT } - - DX_RELEASE(m_backBufferDepthStencil, 0); } + DX_RELEASE(m_backBufferDepthStencil, 0); + for (uint32_t ii = 0; ii < BX_COUNTOF(m_frameBuffers); ++ii) { m_frameBuffers[ii].preReset(); @@ -4461,7 +4461,12 @@ namespace bgfx { namespace d3d12 return; } - device->CreateUnorderedAccessView(_texture.m_ptr + ID3D12Resource* resource = NULL != _texture.m_singleMsaa + ? _texture.m_singleMsaa + : _texture.m_ptr + ; + + device->CreateUnorderedAccessView(resource , NULL , &uavd , cpuHandle @@ -6753,11 +6758,28 @@ namespace bgfx { namespace d3d12 if (autoGenMips && renderTarget - && 1 < m_numMips - && NULL == m_singleMsaa - ) + && 1 < m_numMips) { - s_renderD3D12->generateMips(_commandList, *this); + if (NULL != m_singleMsaa) + { + setResourceBarrier(_commandList + , m_singleMsaa + , D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE + , D3D12_RESOURCE_STATE_UNORDERED_ACCESS + ); + + s_renderD3D12->generateMips(_commandList, *this); + + setResourceBarrier(_commandList + , m_singleMsaa + , D3D12_RESOURCE_STATE_UNORDERED_ACCESS + , D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE + ); + } + else + { + s_renderD3D12->generateMips(_commandList, *this); + } } } @@ -6805,8 +6827,11 @@ namespace bgfx { namespace d3d12 uint16_t samplerStateIdx = getSamplerState(samplerFlags, BGFX_MAX_COMPUTE_BINDINGS, NULL); _commandList->SetComputeRootDescriptorTable(ComputeRp::Sampler, m_samplerAllocator.get(samplerStateIdx) ); - D3D12_RESOURCE_STATES prevState = _texture.setState(_commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); - BX_UNUSED(prevState); + if (NULL == _texture.m_singleMsaa) + { + D3D12_RESOURCE_STATES prevState = _texture.setState(_commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + BX_UNUSED(prevState); + } const uint32_t numSlices = (TextureD3D12::TextureCube == _texture.m_type ? 6 : 1) * bx::max(_texture.m_numLayers, 1) @@ -6902,7 +6927,7 @@ namespace bgfx { namespace d3d12 D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = _texture.m_ptr; + barrier.UAV.pResource = NULL != _texture.m_singleMsaa ? _texture.m_singleMsaa : _texture.m_ptr; _commandList->ResourceBarrier(1, &barrier); topMip += numMips; @@ -7548,7 +7573,18 @@ namespace bgfx { namespace d3d12 { if (D3D12_RESOURCE_STATES(UINT32_MAX) != state) { - m_textures[currentSrc.idx].setState(m_commandList, state); + TextureD3D12& prev = m_textures[currentSrc.idx]; + + if (NULL != prev.m_singleMsaa) + { + setResourceBarrier(m_commandList + , prev.m_singleMsaa + , D3D12_RESOURCE_STATE_COPY_SOURCE + , D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE + ); + } + + prev.setState(m_commandList, state); } currentSrc = blit.m_src.to(); @@ -7633,22 +7669,23 @@ namespace bgfx { namespace d3d12 , depthStencil ? NULL : &box ); } - - if (NULL != src.m_singleMsaa) - { - setResourceBarrier( - m_commandList - , src.m_singleMsaa - , D3D12_RESOURCE_STATE_COPY_SOURCE - , D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE - ); - } } if (isValid(currentSrc) && D3D12_RESOURCE_STATES(UINT32_MAX) != state) { - m_textures[currentSrc.idx].setState(m_commandList, state); + TextureD3D12& src = m_textures[currentSrc.idx]; + + if (NULL != src.m_singleMsaa) + { + setResourceBarrier(m_commandList + , src.m_singleMsaa + , D3D12_RESOURCE_STATE_COPY_SOURCE + , D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE + ); + } + + src.setState(m_commandList, state); } } diff --git a/src/renderer_mtl.h b/src/renderer_mtl.h index a5f3094e1..6f6c89b3d 100644 --- a/src/renderer_mtl.h +++ b/src/renderer_mtl.h @@ -565,9 +565,9 @@ namespace bgfx { namespace mtl uint32_t m_height; uint16_t m_denseIdx; - TextureHandle m_colorHandle[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1]; + TextureHandle m_colorHandle[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS]; TextureHandle m_depthHandle; - Attachment m_colorAttachment[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1]; + Attachment m_colorAttachment[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS]; Attachment m_depthAttachment; uint8_t m_num; // number of color handles }; diff --git a/src/renderer_vk.cpp b/src/renderer_vk.cpp index 27e7f0375..4ec680262 100644 --- a/src/renderer_vk.cpp +++ b/src/renderer_vk.cpp @@ -6556,7 +6556,6 @@ VK_DESTROY if (m_sampler.Count > 1) { BX_ASSERT(VK_IMAGE_VIEW_TYPE_3D != m_type, "Can't create multisample 3D image."); - BX_ASSERT(m_numMips <= 1, "Can't create multisample image with mip chain."); } VkImageCreateInfo ici; @@ -6614,6 +6613,10 @@ VK_DESTROY : ici.mipLevels ; + BX_ASSERT(1 == m_sampler.Count || ici.mipLevels <= 1 + , "Can't create multisample image with mip chain." + ); + if (0 != _external) { static_assert(sizeof(m_textureImage) == sizeof(_external), "Size must match!"); @@ -7245,6 +7248,84 @@ VK_DESTROY , 1 , &resolve ); + + const bool autoGenMips = true + && 0 != (_resolve & BGFX_RESOLVE_AUTO_GEN_MIPS) + && 0 == (m_flags & BGFX_TEXTURE_RT_WRITE_ONLY) + && (_mip + 1) < m_numMips + ; + + if (autoGenMips) + { + BGFX_PROFILER_SCOPE("Resolve - Generate Mipmaps (MSAA)", kColorResource); + + int32_t mipWidth = bx::max(int32_t(m_width) >> _mip, 1); + int32_t mipHeight = bx::max(int32_t(m_height) >> _mip, 1); + + const VkFilter filter = bimg::isDepth(bimg::TextureFormat::Enum(m_textureFormat) ) + ? VK_FILTER_NEAREST + : VK_FILTER_LINEAR + ; + + VkImageBlit blit; + blit.srcOffsets[0] = { 0, 0, 0 }; + blit.srcSubresource.aspectMask = m_aspectFlags; + blit.srcSubresource.baseArrayLayer = _layer; + blit.srcSubresource.layerCount = numLayers; + blit.dstOffsets[0] = { 0, 0, 0 }; + blit.dstSubresource.aspectMask = m_aspectFlags; + blit.dstSubresource.baseArrayLayer = _layer; + blit.dstSubresource.layerCount = numLayers; + + for (uint32_t i = _mip + 1; i < m_numMips; i++) + { + BGFX_PROFILER_SCOPE("Mipmap", kColorResource); + + blit.srcOffsets[1] = { mipWidth, mipHeight, 1 }; + blit.srcSubresource.mipLevel = i - 1; + + mipWidth = bx::max(mipWidth >> 1, 1); + mipHeight = bx::max(mipHeight >> 1, 1); + + blit.dstOffsets[1] = { mipWidth, mipHeight, 1 }; + blit.dstSubresource.mipLevel = i; + + setImageMemoryBarrier( + _commandBuffer + , m_singleMsaaImage + , m_aspectFlags + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , blit.srcSubresource.mipLevel + , 1 + , _layer + , numLayers + ); + + vkCmdBlitImage( + _commandBuffer + , m_singleMsaaImage + , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , m_singleMsaaImage + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , 1 + , &blit + , filter + ); + } + + setImageMemoryBarrier( + _commandBuffer + , m_singleMsaaImage + , m_aspectFlags + , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , _mip + , m_numMips - _mip - 1 + , _layer + , numLayers + ); + } } if (needMipGen)