Add barrier before use of some modified images

This commit is contained in:
gdk 2022-04-15 21:22:19 -03:00 committed by riperiperi
parent 2852ddf510
commit 7838a45772
13 changed files with 151 additions and 20 deletions

View file

@ -1,3 +1,4 @@
using Ryujinx.Graphics.Shader;
using System;
namespace Ryujinx.Graphics.GAL
@ -83,7 +84,7 @@ namespace Ryujinx.Graphics.GAL
void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers);
void SetTextureAndSampler(int binding, ITexture texture, ISampler sampler);
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers);

View file

@ -1,17 +1,20 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetTextureAndSamplerCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetTextureAndSampler;
private ShaderStage _stage;
private int _binding;
private TableRef<ITexture> _texture;
private TableRef<ISampler> _sampler;
public void Set(int binding, TableRef<ITexture> texture, TableRef<ISampler> sampler)
public void Set(ShaderStage stage, int binding, TableRef<ITexture> texture, TableRef<ISampler> sampler)
{
_stage = stage;
_binding = binding;
_texture = texture;
_sampler = sampler;
@ -19,7 +22,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
public static void Run(ref SetTextureAndSamplerCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetTextureAndSampler(command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base, command._sampler.GetAs<ThreadedSampler>(threaded)?.Base);
renderer.Pipeline.SetTextureAndSampler(command._stage, command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base, command._sampler.GetAs<ThreadedSampler>(threaded)?.Base);
}
}
}

View file

@ -1,6 +1,7 @@
using Ryujinx.Graphics.GAL.Multithreading.Commands;
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using Ryujinx.Graphics.Shader;
using System;
using System.Linq;
@ -262,9 +263,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand();
}
public void SetTextureAndSampler(int binding, ITexture texture, ISampler sampler)
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
{
_renderer.New<SetTextureAndSamplerCommand>().Set(binding, Ref(texture), Ref(sampler));
_renderer.New<SetTextureAndSamplerCommand>().Set(stage, binding, Ref(texture), Ref(sampler));
_renderer.QueueCommand();
}

View file

@ -559,7 +559,7 @@ namespace Ryujinx.Graphics.Gpu.Image
state.ScaleIndex = index;
state.UsageFlags = usageFlags;
_context.Renderer.Pipeline.SetTextureAndSampler(bindingInfo.Binding, hostTextureRebind, state.Sampler);
_context.Renderer.Pipeline.SetTextureAndSampler(stage, bindingInfo.Binding, hostTextureRebind, state.Sampler);
}
continue;
@ -582,7 +582,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// Ensure that the buffer texture is using the correct buffer as storage.
// Buffers are frequently re-created to accomodate larger data, so we need to re-bind
// to ensure we're not using a old buffer that was already deleted.
_channel.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
}
else
{
@ -599,7 +599,7 @@ namespace Ryujinx.Graphics.Gpu.Image
state.Sampler = hostSampler;
_context.Renderer.Pipeline.SetTextureAndSampler(bindingInfo.Binding, hostTexture, hostSampler);
_context.Renderer.Pipeline.SetTextureAndSampler(stage, bindingInfo.Binding, hostTexture, hostSampler);
}
state.CachedTexture = texture;
@ -715,7 +715,7 @@ namespace Ryujinx.Graphics.Gpu.Image
format = texture.Format;
}
_channel.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
}
else
{

View file

@ -435,7 +435,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
else
{
_context.Renderer.Pipeline.SetTextureAndSampler(binding.BindingInfo.Binding, binding.Texture, null);
_context.Renderer.Pipeline.SetTextureAndSampler(binding.Stage, binding.BindingInfo.Binding, binding.Texture, null);
}
}
@ -719,17 +719,25 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary>
/// Sets the buffer storage of a buffer texture. This will be bound when the buffer manager commits bindings.
/// </summary>
/// <param name="stage">Shader stage accessing the texture</param>
/// <param name="texture">Buffer texture</param>
/// <param name="address">Address of the buffer in memory</param>
/// <param name="size">Size of the buffer in bytes</param>
/// <param name="bindingInfo">Binding info for the buffer texture</param>
/// <param name="format">Format of the buffer texture</param>
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
public void SetBufferTextureStorage(ITexture texture, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage)
public void SetBufferTextureStorage(
ShaderStage stage,
ITexture texture,
ulong address,
ulong size,
TextureBindingInfo bindingInfo,
Format format,
bool isImage)
{
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(address, size);
_bufferTextures.Add(new BufferTextureBinding(texture, address, size, bindingInfo, format, isImage));
_bufferTextures.Add(new BufferTextureBinding(stage, texture, address, size, bindingInfo, format, isImage));
}
/// <summary>

View file

@ -1,5 +1,6 @@
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.Gpu.Memory
{
@ -8,6 +9,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary>
struct BufferTextureBinding
{
/// <summary>
/// Shader stage accessing the texture.
/// </summary>
public ShaderStage Stage { get; }
/// <summary>
/// The buffer texture.
/// </summary>
@ -41,14 +47,23 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary>
/// Create a new buffer texture binding.
/// </summary>
/// <param name="stage">Shader stage accessing the texture</param>
/// <param name="texture">Buffer texture</param>
/// <param name="address">Base address</param>
/// <param name="size">Size in bytes</param>
/// <param name="bindingInfo">Binding info</param>
/// <param name="format">Binding format</param>
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
public BufferTextureBinding(ITexture texture, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage)
public BufferTextureBinding(
ShaderStage stage,
ITexture texture,
ulong address,
ulong size,
TextureBindingInfo bindingInfo,
Format format,
bool isImage)
{
Stage = stage;
Texture = texture;
Address = address;
Size = size;

View file

@ -1195,7 +1195,7 @@ namespace Ryujinx.Graphics.OpenGL
SetBuffers(first, buffers, isStorage: true);
}
public void SetTextureAndSampler(int binding, ITexture texture, ISampler sampler)
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
{
if (texture != null)
{

View file

@ -167,7 +167,7 @@ namespace Ryujinx.Graphics.Vulkan
SignalDirty(DirtyFlags.Storage);
}
public void SetTextureAndSampler(int binding, ITexture texture, ISampler sampler)
public void SetTextureAndSampler(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture texture, ISampler sampler)
{
if (texture == null)
{
@ -195,7 +195,11 @@ namespace Ryujinx.Graphics.Vulkan
Array.Resize(ref _samplerRefs, binding + 1);
}
_textureRefs[binding] = ((TextureView)texture).GetImageView();
TextureView view = (TextureView)texture;
view.Storage.InsertBarrier(cbs, AccessFlags.AccessShaderReadBit, stage.ConvertToPipelineStageFlags());
_textureRefs[binding] = view.GetImageView();
_samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();
_textures[binding] = new DescriptorImageInfo()

View file

@ -30,6 +30,29 @@ namespace Ryujinx.Graphics.Vulkan
return 0;
}
public static PipelineStageFlags ConvertToPipelineStageFlags(this ShaderStage stage)
{
switch (stage)
{
case ShaderStage.Vertex:
return PipelineStageFlags.PipelineStageVertexShaderBit;
case ShaderStage.Geometry:
return PipelineStageFlags.PipelineStageGeometryShaderBit;
case ShaderStage.TessellationControl:
return PipelineStageFlags.PipelineStageTessellationControlShaderBit;
case ShaderStage.TessellationEvaluation:
return PipelineStageFlags.PipelineStageTessellationEvaluationShaderBit;
case ShaderStage.Fragment:
return PipelineStageFlags.PipelineStageFragmentShaderBit;
case ShaderStage.Compute:
return PipelineStageFlags.PipelineStageComputeShaderBit;
};
Logger.Debug?.Print(LogClass.Gpu, $"Invalid {nameof(ShaderStage)} enum value: {stage}.");
return 0;
}
public static SamplerAddressMode Convert(this AddressMode mode)
{
switch (mode)

View file

@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.Vulkan
{
private readonly Device _device;
private readonly Auto<DisposableImageView>[] _attachments;
private readonly TextureView[] _colors;
private readonly TextureView _depthStencil;
private uint _validColorAttachments;
public uint Width { get; }
@ -59,6 +61,7 @@ namespace Ryujinx.Graphics.Vulkan
int count = colorsCount + (IsValidTextureView(depthStencil) ? 1 : 0);
_attachments = new Auto<DisposableImageView>[count];
_colors = new TextureView[colorsCount];
AttachmentSamples = new uint[count];
AttachmentFormats = new VkFormat[count];
@ -79,6 +82,7 @@ namespace Ryujinx.Graphics.Vulkan
var texture = (TextureView)color;
_attachments[index] = texture.GetImageViewForAttachment();
_colors[index] = texture;
_validColorAttachments |= 1u << bindIndex;
AttachmentSamples[index] = (uint)texture.Info.Samples;
@ -101,6 +105,7 @@ namespace Ryujinx.Graphics.Vulkan
if (depthStencil is TextureView dsTexture && dsTexture.Valid)
{
_attachments[count - 1] = dsTexture.GetImageViewForAttachment();
_depthStencil = dsTexture;
AttachmentSamples[count - 1] = (uint)dsTexture.Info.Samples;
AttachmentFormats[count - 1] = dsTexture.VkFormat;
@ -177,5 +182,22 @@ namespace Ryujinx.Graphics.Vulkan
api.CreateFramebuffer(_device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError();
return new Auto<DisposableFramebuffer>(new DisposableFramebuffer(api, _device, framebuffer), null, _attachments);
}
public void UpdateModifications()
{
if (_colors != null)
{
for (int index = 0; index < _colors.Length; index++)
{
_colors[index].Storage.SetModification(
AccessFlags.AccessColorAttachmentWriteBit,
PipelineStageFlags.PipelineStageColorAttachmentOutputBit);
}
}
_depthStencil?.Storage.SetModification(
AccessFlags.AccessDepthStencilAttachmentWriteBit,
PipelineStageFlags.PipelineStageColorAttachmentOutputBit);
}
}
}

View file

@ -190,7 +190,7 @@ void main()
var sampler = linearFilter ? _samplerLinear : _samplerNearest;
_pipeline.SetTextureAndSampler(Constants.MaxTexturesPerStage, src, sampler);
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, Constants.MaxTexturesPerStage, src, sampler);
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
@ -327,7 +327,7 @@ void main()
{
const int RegionBufferSize = 16;
pipeline.SetTextureAndSampler(Constants.MaxTexturesPerStage, src, srcSampler);
pipeline.SetTextureAndSampler(ShaderStage.Fragment, Constants.MaxTexturesPerStage, src, srcSampler);
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];

View file

@ -627,6 +627,7 @@ namespace Ryujinx.Graphics.Vulkan
public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
{
FramebufferParams?.UpdateModifications();
CreateFramebuffer(colors, depthStencil);
CreateRenderPass();
SignalStateChange();
@ -710,9 +711,9 @@ namespace Ryujinx.Graphics.Vulkan
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers);
}
public void SetTextureAndSampler(int binding, ITexture texture, ISampler sampler)
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
{
_descriptorSetUpdater.SetTextureAndSampler(binding, texture, sampler);
_descriptorSetUpdater.SetTextureAndSampler(Cbs, stage, binding, texture, sampler);
}
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)

View file

@ -43,6 +43,9 @@ namespace Ryujinx.Graphics.Vulkan
private Dictionary<GAL.Format, TextureStorage> _aliasedStorages;
private AccessFlags _lastModificationAccess;
private PipelineStageFlags _lastModificationStage;
public VkFormat VkFormat { get; }
public float ScaleFactor { get; }
@ -399,6 +402,56 @@ namespace Ryujinx.Graphics.Vulkan
return Info.Format == GAL.Format.D24UnormS8Uint && VkFormat == VkFormat.D32SfloatS8Uint;
}
public void SetModification(AccessFlags accessFlags, PipelineStageFlags stage)
{
_lastModificationAccess = accessFlags;
_lastModificationStage = stage;
}
public void InsertBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
{
if (_lastModificationAccess != AccessFlags.AccessNoneKhr)
{
ImageAspectFlags aspectFlags;
if (_info.Format.IsDepthOrStencil())
{
if (_info.Format == GAL.Format.S8Uint)
{
aspectFlags = ImageAspectFlags.ImageAspectStencilBit;
}
else if (_info.Format == GAL.Format.D16Unorm || _info.Format == GAL.Format.D32Float)
{
aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
}
else
{
aspectFlags = ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit;
}
}
else
{
aspectFlags = ImageAspectFlags.ImageAspectColorBit;
}
TextureView.InsertImageBarrier(
_gd.Api,
cbs.CommandBuffer,
_imageAuto.Get(cbs).Value,
_lastModificationAccess,
dstAccessFlags,
_lastModificationStage,
dstStageFlags,
aspectFlags,
0,
0,
_info.GetLayers(),
_info.Levels);
_lastModificationAccess = AccessFlags.AccessNoneKhr;
}
}
public void Dispose()
{
if (_aliasedStorages != null)