diff --git a/src/util/d3d12_device.cpp b/src/util/d3d12_device.cpp index b9f454868..6b7301579 100644 --- a/src/util/d3d12_device.cpp +++ b/src/util/d3d12_device.cpp @@ -1659,22 +1659,45 @@ void D3D12Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTextu { DebugAssert( !(flags & (GPUPipeline::RenderPassFlag::ColorFeedbackLoop | GPUPipeline::RenderPassFlag::SampleDepthBuffer))); + + const bool image_bind_changed = ((m_current_render_pass_flags ^ flags) & GPUPipeline::BindRenderTargetsAsImages); + bool changed = + (m_num_current_render_targets != num_rts || m_current_depth_target != ds || m_current_render_pass_flags != flags); + bool needs_ds_clear = (ds && ds->IsClearedOrInvalidated()); + bool needs_rt_clear = false; + if (InRenderPass()) EndRenderPass(); m_current_depth_target = static_cast(ds); - if (num_rts > 0) - std::memcpy(m_current_render_targets.data(), rts, sizeof(D3D12Texture*) * num_rts); + for (u32 i = 0; i < num_rts; i++) + { + D3D12Texture* const RT = static_cast(rts[i]); + changed |= m_current_render_targets[i] != RT; + m_current_render_targets[i] = RT; + needs_rt_clear |= RT->IsClearedOrInvalidated(); + } for (u32 i = num_rts; i < m_num_current_render_targets; i++) m_current_render_targets[i] = nullptr; - m_num_current_render_targets = num_rts; - - // Need a root signature change if switching to UAVs. - m_dirty_flags |= - ((m_current_render_pass_flags ^ flags) & GPUPipeline::BindRenderTargetsAsImages) ? LAYOUT_DEPENDENT_DIRTY_STATE : 0; - m_dirty_flags = (flags & GPUPipeline::BindRenderTargetsAsImages) ? (m_dirty_flags | DIRTY_FLAG_RT_UAVS) : - (m_dirty_flags & ~DIRTY_FLAG_RT_UAVS); + m_num_current_render_targets = Truncate8(num_rts); m_current_render_pass_flags = flags; + + // Don't end render pass unless it's necessary. + if (changed) + { + if (InRenderPass()) + EndRenderPass(); + + // Need a root signature change if switching to UAVs. + m_dirty_flags |= image_bind_changed ? LAYOUT_DEPENDENT_DIRTY_STATE : 0; + m_dirty_flags = (flags & GPUPipeline::BindRenderTargetsAsImages) ? (m_dirty_flags | DIRTY_FLAG_RT_UAVS) : + (m_dirty_flags & ~DIRTY_FLAG_RT_UAVS); + } + else if (needs_rt_clear || needs_ds_clear) + { + if (InRenderPass()) + EndRenderPass(); + } } void D3D12Device::BeginRenderPass() diff --git a/src/util/d3d12_device.h b/src/util/d3d12_device.h index 040a6e290..bad70729d 100644 --- a/src/util/d3d12_device.h +++ b/src/util/d3d12_device.h @@ -338,7 +338,7 @@ private: D3D12Pipeline* m_current_pipeline = nullptr; D3D12_PRIMITIVE_TOPOLOGY m_current_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - u32 m_num_current_render_targets = 0; + u8 m_num_current_render_targets = 0; GPUPipeline::RenderPassFlag m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags; std::array m_current_render_targets = {}; D3D12Texture* m_current_depth_target = nullptr; diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index 7bfd09e70..b4848c842 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -3318,10 +3318,9 @@ void VulkanDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUText DIRTY_FLAG_INPUT_ATTACHMENT : 0); } - - // TODO: This could use vkCmdClearAttachments() instead. - if (needs_rt_clear || needs_ds_clear) + else if (needs_rt_clear || needs_ds_clear) { + // TODO: This could use vkCmdClearAttachments() instead. if (InRenderPass()) EndRenderPass(); }