Vulkan: Insert barriers before clears (#4596)
* Vulkan: Insert barriers before clears Newer NVIDIA GPUs seem to be able to start clearing render targets before the last rasterization task is completed, which can cause it to clear a texture while it is being sampled. This change adds a barrier from read to write when doing a clear, assuming it has been sampled in the past. It could be possible for this to be needed for sample into draw by some GPU, but it's not right now afaik. This should fix visual artifacts on newer NVIDIA GPUs and driver combos. Contrary to popular belief, Tetris® Effect: Connected is not affected. Testing welcome, hopefully should fix most cases of this and not cost too much performance. * Visual Studio Moment * Address feedback * Address Feedback 2
This commit is contained in:
parent
21ce8a9b80
commit
a34fb0e939
5 changed files with 56 additions and 24 deletions
|
@ -236,7 +236,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
else if (texture is TextureView view)
|
else if (texture is TextureView view)
|
||||||
{
|
{
|
||||||
view.Storage.InsertBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
view.Storage.InsertWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||||
|
|
||||||
_textureRefs[binding] = view.GetImageView();
|
_textureRefs[binding] = view.GetImageView();
|
||||||
_samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();
|
_samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();
|
||||||
|
|
|
@ -218,5 +218,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
AccessFlags.DepthStencilAttachmentWriteBit,
|
AccessFlags.DepthStencilAttachmentWriteBit,
|
||||||
PipelineStageFlags.ColorAttachmentOutputBit);
|
PipelineStageFlags.ColorAttachmentOutputBit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InsertClearBarrier(CommandBufferScoped cbs, int index)
|
||||||
|
{
|
||||||
|
if (_colors != null)
|
||||||
|
{
|
||||||
|
int realIndex = Array.IndexOf(AttachmentIndices, index);
|
||||||
|
|
||||||
|
if (realIndex != -1)
|
||||||
|
{
|
||||||
|
_colors[realIndex].Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.ColorAttachmentWriteBit, PipelineStageFlags.ColorAttachmentOutputBit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertClearBarrierDS(CommandBufferScoped cbs)
|
||||||
|
{
|
||||||
|
_depthStencil?.Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.DepthStencilAttachmentWriteBit, PipelineStageFlags.EarlyFragmentTestsBit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,6 +226,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue);
|
var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue);
|
||||||
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
||||||
|
|
||||||
|
FramebufferParams.InsertClearBarrier(Cbs, index);
|
||||||
|
|
||||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,6 +258,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
var attachment = new ClearAttachment(flags, 0, clearValue);
|
var attachment = new ClearAttachment(flags, 0, clearValue);
|
||||||
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
||||||
|
|
||||||
|
FramebufferParams.InsertClearBarrierDS(Cbs);
|
||||||
|
|
||||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
private AccessFlags _lastModificationAccess;
|
private AccessFlags _lastModificationAccess;
|
||||||
private PipelineStageFlags _lastModificationStage;
|
private PipelineStageFlags _lastModificationStage;
|
||||||
|
private AccessFlags _lastReadAccess;
|
||||||
|
private PipelineStageFlags _lastReadStage;
|
||||||
|
|
||||||
private int _viewsCount;
|
private int _viewsCount;
|
||||||
private ulong _size;
|
private ulong _size;
|
||||||
|
@ -440,31 +442,39 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_lastModificationStage = stage;
|
_lastModificationStage = stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InsertBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
|
public void InsertReadToWriteBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
|
||||||
{
|
{
|
||||||
|
if (_lastReadAccess != AccessFlags.NoneKhr)
|
||||||
|
{
|
||||||
|
ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
|
||||||
|
|
||||||
|
TextureView.InsertImageBarrier(
|
||||||
|
_gd.Api,
|
||||||
|
cbs.CommandBuffer,
|
||||||
|
_imageAuto.Get(cbs).Value,
|
||||||
|
_lastReadAccess,
|
||||||
|
dstAccessFlags,
|
||||||
|
_lastReadStage,
|
||||||
|
dstStageFlags,
|
||||||
|
aspectFlags,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
_info.GetLayers(),
|
||||||
|
_info.Levels);
|
||||||
|
|
||||||
|
_lastReadAccess = AccessFlags.NoneKhr;
|
||||||
|
_lastReadStage = PipelineStageFlags.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertWriteToReadBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
|
||||||
|
{
|
||||||
|
_lastReadAccess |= dstAccessFlags;
|
||||||
|
_lastReadStage |= dstStageFlags;
|
||||||
|
|
||||||
if (_lastModificationAccess != AccessFlags.NoneKhr)
|
if (_lastModificationAccess != AccessFlags.NoneKhr)
|
||||||
{
|
{
|
||||||
ImageAspectFlags aspectFlags;
|
ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
|
||||||
|
|
||||||
if (_info.Format.IsDepthOrStencil())
|
|
||||||
{
|
|
||||||
if (_info.Format == GAL.Format.S8Uint)
|
|
||||||
{
|
|
||||||
aspectFlags = ImageAspectFlags.StencilBit;
|
|
||||||
}
|
|
||||||
else if (_info.Format == GAL.Format.D16Unorm || _info.Format == GAL.Format.D32Float)
|
|
||||||
{
|
|
||||||
aspectFlags = ImageAspectFlags.DepthBit;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aspectFlags = ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aspectFlags = ImageAspectFlags.ColorBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
_gd.Api,
|
_gd.Api,
|
||||||
|
|
Reference in a new issue