Fix MSAA blit into a multisampled destination and stale MSAA resolve. (#3921)

This commit is contained in:
Branimir Karadžić
2026-08-23 04:44:43 +00:00
committed by GitHub
parent dd961560d5
commit 780f7bf00a
6 changed files with 135 additions and 20 deletions
+12 -3
View File
@@ -5442,7 +5442,7 @@ namespace bgfx { namespace d3d11
for (uint32_t ii = _layer, end = _layer + _numLayers; ii < end; ++ii)
{
const UINT resource = _mip + (ii * m_numMips);
deviceCtx->ResolveSubresource(m_texture2d, resource, m_rt, resource, resolveFormat);
deviceCtx->ResolveSubresource(m_texture2d, resource, m_rt, ii, resolveFormat);
}
}
@@ -6122,6 +6122,15 @@ namespace bgfx { namespace d3d11
const TextureD3D11& src = m_textures[blit.m_src.idx];
const TextureD3D11& dst = m_textures[blit.m_dst.idx];
const bool srcReadsMsaaRt = NULL != src.m_rt && dst.isMsaaSurface();
if (NULL != src.m_rt
&& !srcReadsMsaaRt
&& 0 == blit.m_srcMip)
{
src.resolve(BGFX_RESOLVE_NONE, blit.m_srcZ, 1, 0);
}
if ( src.isMsaaSurface()
&& !dst.isMsaaSurface()
&& TextureD3D11::Texture3D != src.m_type)
@@ -6229,7 +6238,7 @@ namespace bgfx { namespace d3d11
, "When blitting depthstencil surface, source resolution must match destination."
);
const bool msaaToMsaa = src.isMsaaSurface() && dst.isMsaaSurface();
const bool msaaToMsaa = (src.isMsaaSurface() || srcReadsMsaaRt) && dst.isMsaaSurface();
const bool wholeSubResource = depthStencil || msaaToMsaa;
const D3D11_BOX box =
@@ -6251,7 +6260,7 @@ namespace bgfx { namespace d3d11
, wholeSubResource ? 0 : blit.m_dstX
, wholeSubResource ? 0 : blit.m_dstY
, 0
, src.m_ptr
, srcReadsMsaaRt ? src.m_rt : src.m_ptr
, srcZ*src.m_numMips+blit.m_srcMip
, wholeSubResource ? NULL : &box
);
+30 -7
View File
@@ -7062,6 +7062,14 @@ namespace bgfx { namespace d3d12
, D3D12_RESOURCE_STATE_RESOLVE_DEST
);
const TextureFormatInfo& tfi = s_textureFormat[m_textureFormat];
const bool useSrgb = true
&& 0 != (m_flags & BGFX_TEXTURE_SRGB)
&& !bimg::isDepth(bimg::TextureFormat::Enum(m_textureFormat) )
&& DXGI_FORMAT_UNKNOWN != tfi.m_fmtSrgb
;
const DXGI_FORMAT resolveFormat = useSrgb ? tfi.m_fmtSrgb : tfi.m_fmt;
for (uint32_t ii = _layer, end = _layer + _numLayers; ii < end; ++ii)
{
const uint32_t resource = _mip + (ii * m_numMips);
@@ -7070,7 +7078,7 @@ namespace bgfx { namespace d3d12
, resource
, m_ptr
, resource
, s_textureFormat[m_textureFormat].m_fmt
, resolveFormat
);
}
@@ -7122,6 +7130,12 @@ namespace bgfx { namespace d3d12
;
}
bool TextureD3D12::isMultisampled() const
{
const uint32_t msaaQuality = bx::satSub<uint32_t>(uint32_t( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT), 1u);
return 1 < s_msaa[msaaQuality].Count;
}
D3D12_RESOURCE_STATES TextureD3D12::setState(ID3D12GraphicsCommandList* _commandList, D3D12_RESOURCE_STATES _state)
{
if (m_state != _state)
@@ -7753,10 +7767,10 @@ namespace bgfx { namespace d3d12
{
ID3D12GraphicsCommandList* commandList = s_renderD3D12->m_commandList;
Query& query = m_query[_idx];
Query& query = m_query[_idx];
query.m_ready = true;
query.m_fence = s_renderD3D12->m_cmd.m_currentFence - 1;
uint32_t offset = _idx * 2;
query.m_fence = s_renderD3D12->m_cmd.m_currentFence;
const uint32_t offset = _idx * 2;
commandList->EndQuery(m_queryHeap
, D3D12_QUERY_TYPE_TIMESTAMP
@@ -7873,7 +7887,7 @@ namespace bgfx { namespace d3d12
, m_readback
, handle.idx * sizeof(uint64_t)
);
m_fence[idx] = s_renderD3D12->m_cmd.m_currentFence - 1;
m_fence[idx] = s_renderD3D12->m_cmd.m_currentFence;
m_control.commit(1);
}
@@ -7956,6 +7970,13 @@ namespace bgfx { namespace d3d12
if (currentSrc.idx != blit.m_src.idx)
{
if (NULL != src.m_singleMsaa
&& !dst.isMultisampled()
&& 0 == blit.m_srcMip)
{
src.resolve(m_commandList, BGFX_RESOLVE_NONE, blit.m_srcZ, 1, 0);
}
if (D3D12_RESOURCE_STATES(UINT32_MAX) != srcState)
{
TextureD3D12& prev = m_textures[currentSrc.idx];
@@ -8094,7 +8115,7 @@ namespace bgfx { namespace d3d12
const D3D12_TEXTURE_COPY_LOCATION srcLocation =
{
.pResource = NULL != src.m_singleMsaa ? src.m_singleMsaa : src.m_ptr,
.pResource = NULL != src.m_singleMsaa && !dst.isMultisampled() ? src.m_singleMsaa : src.m_ptr,
.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
.SubresourceIndex = srcZ*src.m_numMips+blit.m_srcMip,
};
@@ -8238,7 +8259,7 @@ namespace bgfx { namespace d3d12
UniformCacheState ucs(_render);
BlitState bs(_render);
uint32_t blendFactor = 0;
uint32_t blendFactor = UINT32_MAX;
const uint64_t primType = _render->m_debug&BGFX_DEBUG_WIREFRAME ? BGFX_STATE_PT_LINES : 0;
uint8_t primIndex = uint8_t(primType >> BGFX_STATE_PT_SHIFT);
@@ -8442,6 +8463,7 @@ namespace bgfx { namespace d3d12
if (commandListChanged)
{
commandListChanged = false;
blendFactor = UINT32_MAX;
m_commandList->SetComputeRootSignature(m_computeRootSignature);
ID3D12DescriptorHeap* heaps[] = {
@@ -8762,6 +8784,7 @@ namespace bgfx { namespace d3d12
{
wasCompute = false;
commandListChanged = false;
blendFactor = UINT32_MAX;
m_commandList->SetGraphicsRootSignature(m_rootSignature);
ID3D12DescriptorHeap* heaps[] = {
+1
View File
@@ -457,6 +457,7 @@ namespace bgfx { namespace d3d12
void resolve(ID3D12GraphicsCommandList* _commandList, uint8_t _resolve, uint32_t _layer, uint32_t _numLayers, uint32_t _mip);
D3D12_RESOURCE_STATES setState(ID3D12GraphicsCommandList* _commandList, D3D12_RESOURCE_STATES _state);
bool isMsaaSurface() const;
bool isMultisampled() const;
D3D12_SHADER_RESOURCE_VIEW_DESC m_srvd;
D3D12_UNORDERED_ACCESS_VIEW_DESC m_uavd;
+62 -4
View File
@@ -7605,6 +7605,51 @@ namespace bgfx { namespace gl
return true;
}
static void resolveMsaaRbo(const TextureGL& _src, GLuint _currentFbo)
{
if (0 == _src.m_rbo
|| NULL == glBlitFramebuffer
|| bimg::isDepth(bimg::TextureFormat::Enum(_src.m_textureFormat) ) )
{
return;
}
GLuint fbo[2];
GL_CHECK(glGenFramebuffers(BX_COUNTOF(fbo), fbo) );
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[0]) );
GL_CHECK(glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_RENDERBUFFER
, _src.m_rbo
) );
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]) );
GL_CHECK(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, _src.m_target
, _src.m_id
, 0
) );
GL_CHECK(glDisable(GL_SCISSOR_TEST) );
GL_CHECK(glBlitFramebuffer(
0
, 0
, _src.m_width
, _src.m_height
, 0
, 0
, _src.m_width
, _src.m_height
, GL_COLOR_BUFFER_BIT
, GL_NEAREST
) );
GL_CHECK(glDeleteFramebuffers(BX_COUNTOF(fbo), fbo) );
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, _currentFbo) );
}
static bool blitCompressed2D(
const BlitItem& _bi
, const TextureGL& _src
@@ -7742,13 +7787,21 @@ namespace bgfx { namespace gl
continue;
}
const bool srcReadsMsaaRbo = 0 != src.m_rbo && dst.isMsaaSurface();
if (!srcReadsMsaaRbo
&& 0 == bi.m_srcMip)
{
resolveMsaaRbo(src, m_currentFbo);
}
GL_CHECK(glCopyImageSubData(
src.m_id
, src.m_target
, bi.m_srcMip
srcReadsMsaaRbo ? src.m_rbo : src.m_id
, srcReadsMsaaRbo ? GL_RENDERBUFFER : src.m_target
, srcReadsMsaaRbo ? 0 : bi.m_srcMip
, bi.m_srcX
, bi.m_srcY
, bi.m_srcZ
, srcReadsMsaaRbo ? 0 : bi.m_srcZ
, dst.m_id
, dst.m_target
, bi.m_dstMip
@@ -7774,6 +7827,11 @@ namespace bgfx { namespace gl
, "Blitting 3D regions is not supported"
);
if (0 == bi.m_srcMip)
{
resolveMsaaRbo(src, m_currentFbo);
}
GLuint fbo;
GL_CHECK(glGenFramebuffers(1, &fbo) );
+8
View File
@@ -1465,6 +1465,14 @@ namespace bgfx { namespace gl
;
}
bool isMsaaSurface() const
{
return 0
|| GL_TEXTURE_2D_MULTISAMPLE == m_target
|| GL_TEXTURE_2D_MULTISAMPLE_ARRAY == m_target
;
}
GLuint m_id;
GLuint m_rbo;
GLenum m_target;
+22 -6
View File
@@ -9530,6 +9530,14 @@ VK_DESTROY
BX_ASSERT(false, "Removing external texture failed!");
}
static bool blitReadsSingleMsaa(const TextureVK& _src, const TextureVK& _dst)
{
return true
&& VK_NULL_HANDLE != _src.m_singleMsaaImage
&& 1 == _dst.m_sampler.Count
;
}
void RendererContextVK::submitBlitBatch(BlitState& _bs, uint16_t _view)
{
constexpr uint32_t kMaxItems = 128;
@@ -9550,7 +9558,13 @@ VK_DESTROY
TextureVK& src = m_textures[blit.m_src.idx];
TextureVK& dst = m_textures[blit.m_dst.idx];
srcLayouts[item] = VK_NULL_HANDLE != src.m_singleMsaaImage
if (blitReadsSingleMsaa(src, dst)
&& 0 == blit.m_srcMip)
{
src.resolve(m_commandBuffer, BGFX_RESOLVE_NONE, blit.m_srcZ, 1, 0);
}
srcLayouts[item] = blitReadsSingleMsaa(src, dst)
? src.m_currentSingleMsaaImageLayout
: src.m_currentImageLayout
;
@@ -9566,12 +9580,14 @@ VK_DESTROY
TextureVK& src = m_textures[blit.m_src.idx];
TextureVK& dst = m_textures[blit.m_dst.idx];
const bool srcSingleMsaa = blitReadsSingleMsaa(src, dst);
src.setState(
m_commandBuffer
, blit.m_src.idx == blit.m_dst.idx
? VK_IMAGE_LAYOUT_GENERAL
: VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
, VK_NULL_HANDLE != src.m_singleMsaaImage
, srcSingleMsaa
);
if (blit.m_src.idx != blit.m_dst.idx)
@@ -9579,7 +9595,7 @@ VK_DESTROY
dst.setState(m_commandBuffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
}
const uint16_t srcSamples = VK_NULL_HANDLE != src.m_singleMsaaImage ? 1 : src.m_sampler.Count;
const uint16_t srcSamples = srcSingleMsaa ? 1 : src.m_sampler.Count;
const uint16_t dstSamples = dst.m_sampler.Count;
const bool resolve = true
@@ -9675,8 +9691,8 @@ VK_DESTROY
{
vkCmdCopyImage(
m_commandBuffer
, VK_NULL_HANDLE != src.m_singleMsaaImage ? src.m_singleMsaaImage : src.m_textureImage
, VK_NULL_HANDLE != src.m_singleMsaaImage ? src.m_currentSingleMsaaImageLayout : src.m_currentImageLayout
, srcSingleMsaa ? src.m_singleMsaaImage : src.m_textureImage
, srcSingleMsaa ? src.m_currentSingleMsaaImageLayout : src.m_currentImageLayout
, dst.m_textureImage
, dst.m_currentImageLayout
, 1
@@ -9698,7 +9714,7 @@ VK_DESTROY
TextureVK& src = m_textures[blit.m_src.idx];
TextureVK& dst = m_textures[blit.m_dst.idx];
src.setState(m_commandBuffer, srcLayouts[item], VK_NULL_HANDLE != src.m_singleMsaaImage);
src.setState(m_commandBuffer, srcLayouts[item], blitReadsSingleMsaa(src, dst) );
dst.setState(m_commandBuffer, dstLayouts[item]);
}
}