Better handling for feedback loops.

This commit is contained in:
riperiperi 2024-07-09 00:14:44 +01:00
commit 7ab99e8ea1
5 changed files with 58 additions and 5 deletions

View file

@ -298,19 +298,41 @@ namespace Ryujinx.Graphics.Vulkan
// Generally, we want to avoid this from happening in the future, so flag the texture to immediately // Generally, we want to avoid this from happening in the future, so flag the texture to immediately
// emit a barrier whenever the current render pass is bound again. // emit a barrier whenever the current render pass is bound again.
bool anyIsNonAttachment = false;
foreach (BarrierWithStageFlags<ImageMemoryBarrier, TextureStorage> barrier in _imageBarriers) foreach (BarrierWithStageFlags<ImageMemoryBarrier, TextureStorage> barrier in _imageBarriers)
{ {
rpHolder.AddForcedFence(barrier.Resource, barrier.Flags.Dest); // If the binding is an attachment, don't add it as a forced fence.
bool isAttachment = rpHolder.ContainsAttachment(barrier.Resource);
if (!isAttachment)
{
rpHolder.AddForcedFence(barrier.Resource, barrier.Flags.Dest);
anyIsNonAttachment = true;
}
} }
if (_gd.IsTBDR) if (_gd.IsTBDR)
{ {
if (!_gd.IsMoltenVk) if (!_gd.IsMoltenVk)
{ {
// TBDR GPUs are sensitive to barriers, so we need to end the pass to ensure the data is available. if (!anyIsNonAttachment)
// Metal already has hazard tracking so MVK doesn't need this. {
endRenderPass(); // This case is a feedback loop. To prevent this from causing an absolute performance disaster,
inRenderPass = false; // remove the barriers entirely.
// If this is not here, there will be a lot of single draw render passes.
// TODO: explicit handling for feedback loops, likely outside this class.
_queuedBarrierCount -= _imageBarriers.Count;
_imageBarriers.Clear();
}
else
{
// TBDR GPUs are sensitive to barriers, so we need to end the pass to ensure the data is available.
// Metal already has hazard tracking so MVK doesn't need this.
endRenderPass();
inRenderPass = false;
}
} }
} }
else else

View file

@ -289,6 +289,19 @@ namespace Ryujinx.Graphics.Vulkan
gd.Barriers.Flush(cbs, false, null, null); gd.Barriers.Flush(cbs, false, null, null);
} }
public void AddStoreOpUsage()
{
if (_colors != null)
{
foreach (var color in _colors)
{
color.Storage?.AddStoreOpUsage(false);
}
}
_depthStencil?.Storage?.AddStoreOpUsage(true);
}
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer( public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
VulkanRenderer gd, VulkanRenderer gd,
Device device, Device device,

View file

@ -1639,6 +1639,8 @@ namespace Ryujinx.Graphics.Vulkan
{ {
if (RenderPassActive) if (RenderPassActive)
{ {
FramebufferParams.AddStoreOpUsage();
PauseTransformFeedbackInternal(); PauseTransformFeedbackInternal();
Gd.Api.CmdEndRenderPass(CommandBuffer); Gd.Api.CmdEndRenderPass(CommandBuffer);
SignalRenderPassEnd(); SignalRenderPassEnd();

View file

@ -192,6 +192,11 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
public bool ContainsAttachment(TextureStorage storage)
{
return _textures.Any(view => view.Storage == storage);
}
public void Dispose() public void Dispose()
{ {
// Dispose all framebuffers. // Dispose all framebuffers.

View file

@ -435,6 +435,17 @@ namespace Ryujinx.Graphics.Vulkan
return FormatCapabilities.IsD24S8(Info.Format) && VkFormat == VkFormat.D32SfloatS8Uint; return FormatCapabilities.IsD24S8(Info.Format) && VkFormat == VkFormat.D32SfloatS8Uint;
} }
public void AddStoreOpUsage(bool depthStencil)
{
_lastModificationStage = depthStencil ?
PipelineStageFlags.LateFragmentTestsBit :
PipelineStageFlags.ColorAttachmentOutputBit;
_lastModificationAccess = depthStencil ?
AccessFlags.DepthStencilAttachmentWriteBit :
AccessFlags.ColorAttachmentWriteBit;
}
public void QueueLoadOpBarrier(CommandBufferScoped cbs, bool depthStencil) public void QueueLoadOpBarrier(CommandBufferScoped cbs, bool depthStencil)
{ {
PipelineStageFlags srcStageFlags = _lastReadStage | _lastModificationStage; PipelineStageFlags srcStageFlags = _lastReadStage | _lastModificationStage;