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; using System;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
@ -83,7 +84,7 @@ namespace Ryujinx.Graphics.GAL
void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers); 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 SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
void SetUniformBuffers(int first, 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.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{ {
struct SetTextureAndSamplerCommand : IGALCommand struct SetTextureAndSamplerCommand : IGALCommand
{ {
public CommandType CommandType => CommandType.SetTextureAndSampler; public CommandType CommandType => CommandType.SetTextureAndSampler;
private ShaderStage _stage;
private int _binding; private int _binding;
private TableRef<ITexture> _texture; private TableRef<ITexture> _texture;
private TableRef<ISampler> _sampler; 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; _binding = binding;
_texture = texture; _texture = texture;
_sampler = sampler; _sampler = sampler;
@ -19,7 +22,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
public static void Run(ref SetTextureAndSamplerCommand command, ThreadedRenderer threaded, IRenderer renderer) 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.Commands;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using Ryujinx.Graphics.Shader;
using System; using System;
using System.Linq; using System.Linq;
@ -262,9 +263,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _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(); _renderer.QueueCommand();
} }

View file

@ -559,7 +559,7 @@ namespace Ryujinx.Graphics.Gpu.Image
state.ScaleIndex = index; state.ScaleIndex = index;
state.UsageFlags = usageFlags; state.UsageFlags = usageFlags;
_context.Renderer.Pipeline.SetTextureAndSampler(bindingInfo.Binding, hostTextureRebind, state.Sampler); _context.Renderer.Pipeline.SetTextureAndSampler(stage, bindingInfo.Binding, hostTextureRebind, state.Sampler);
} }
continue; continue;
@ -582,7 +582,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// Ensure that the buffer texture is using the correct buffer as storage. // 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 // 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. // 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 else
{ {
@ -599,7 +599,7 @@ namespace Ryujinx.Graphics.Gpu.Image
state.Sampler = hostSampler; state.Sampler = hostSampler;
_context.Renderer.Pipeline.SetTextureAndSampler(bindingInfo.Binding, hostTexture, hostSampler); _context.Renderer.Pipeline.SetTextureAndSampler(stage, bindingInfo.Binding, hostTexture, hostSampler);
} }
state.CachedTexture = texture; state.CachedTexture = texture;
@ -715,7 +715,7 @@ namespace Ryujinx.Graphics.Gpu.Image
format = texture.Format; 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 else
{ {

View file

@ -435,7 +435,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
} }
else 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> /// <summary>
/// Sets the buffer storage of a buffer texture. This will be bound when the buffer manager commits bindings. /// Sets the buffer storage of a buffer texture. This will be bound when the buffer manager commits bindings.
/// </summary> /// </summary>
/// <param name="stage">Shader stage accessing the texture</param>
/// <param name="texture">Buffer texture</param> /// <param name="texture">Buffer texture</param>
/// <param name="address">Address of the buffer in memory</param> /// <param name="address">Address of the buffer in memory</param>
/// <param name="size">Size of the buffer in bytes</param> /// <param name="size">Size of the buffer in bytes</param>
/// <param name="bindingInfo">Binding info for the buffer texture</param> /// <param name="bindingInfo">Binding info for the buffer texture</param>
/// <param name="format">Format of 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> /// <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); _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> /// <summary>

View file

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

View file

@ -1195,7 +1195,7 @@ namespace Ryujinx.Graphics.OpenGL
SetBuffers(first, buffers, isStorage: true); 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) if (texture != null)
{ {

View file

@ -167,7 +167,7 @@ namespace Ryujinx.Graphics.Vulkan
SignalDirty(DirtyFlags.Storage); 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) if (texture == null)
{ {
@ -195,7 +195,11 @@ namespace Ryujinx.Graphics.Vulkan
Array.Resize(ref _samplerRefs, binding + 1); 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(); _samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();
_textures[binding] = new DescriptorImageInfo() _textures[binding] = new DescriptorImageInfo()

View file

@ -30,6 +30,29 @@ namespace Ryujinx.Graphics.Vulkan
return 0; 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) public static SamplerAddressMode Convert(this AddressMode mode)
{ {
switch (mode) switch (mode)

View file

@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.Vulkan
{ {
private readonly Device _device; private readonly Device _device;
private readonly Auto<DisposableImageView>[] _attachments; private readonly Auto<DisposableImageView>[] _attachments;
private readonly TextureView[] _colors;
private readonly TextureView _depthStencil;
private uint _validColorAttachments; private uint _validColorAttachments;
public uint Width { get; } public uint Width { get; }
@ -59,6 +61,7 @@ namespace Ryujinx.Graphics.Vulkan
int count = colorsCount + (IsValidTextureView(depthStencil) ? 1 : 0); int count = colorsCount + (IsValidTextureView(depthStencil) ? 1 : 0);
_attachments = new Auto<DisposableImageView>[count]; _attachments = new Auto<DisposableImageView>[count];
_colors = new TextureView[colorsCount];
AttachmentSamples = new uint[count]; AttachmentSamples = new uint[count];
AttachmentFormats = new VkFormat[count]; AttachmentFormats = new VkFormat[count];
@ -79,6 +82,7 @@ namespace Ryujinx.Graphics.Vulkan
var texture = (TextureView)color; var texture = (TextureView)color;
_attachments[index] = texture.GetImageViewForAttachment(); _attachments[index] = texture.GetImageViewForAttachment();
_colors[index] = texture;
_validColorAttachments |= 1u << bindIndex; _validColorAttachments |= 1u << bindIndex;
AttachmentSamples[index] = (uint)texture.Info.Samples; AttachmentSamples[index] = (uint)texture.Info.Samples;
@ -101,6 +105,7 @@ namespace Ryujinx.Graphics.Vulkan
if (depthStencil is TextureView dsTexture && dsTexture.Valid) if (depthStencil is TextureView dsTexture && dsTexture.Valid)
{ {
_attachments[count - 1] = dsTexture.GetImageViewForAttachment(); _attachments[count - 1] = dsTexture.GetImageViewForAttachment();
_depthStencil = dsTexture;
AttachmentSamples[count - 1] = (uint)dsTexture.Info.Samples; AttachmentSamples[count - 1] = (uint)dsTexture.Info.Samples;
AttachmentFormats[count - 1] = dsTexture.VkFormat; AttachmentFormats[count - 1] = dsTexture.VkFormat;
@ -177,5 +182,22 @@ namespace Ryujinx.Graphics.Vulkan
api.CreateFramebuffer(_device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError(); api.CreateFramebuffer(_device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError();
return new Auto<DisposableFramebuffer>(new DisposableFramebuffer(api, _device, framebuffer), null, _attachments); 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; 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)]; Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
@ -327,7 +327,7 @@ void main()
{ {
const int RegionBufferSize = 16; 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)]; 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) public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
{ {
FramebufferParams?.UpdateModifications();
CreateFramebuffer(colors, depthStencil); CreateFramebuffer(colors, depthStencil);
CreateRenderPass(); CreateRenderPass();
SignalStateChange(); SignalStateChange();
@ -710,9 +711,9 @@ namespace Ryujinx.Graphics.Vulkan
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers); _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) public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)

View file

@ -43,6 +43,9 @@ namespace Ryujinx.Graphics.Vulkan
private Dictionary<GAL.Format, TextureStorage> _aliasedStorages; private Dictionary<GAL.Format, TextureStorage> _aliasedStorages;
private AccessFlags _lastModificationAccess;
private PipelineStageFlags _lastModificationStage;
public VkFormat VkFormat { get; } public VkFormat VkFormat { get; }
public float ScaleFactor { get; } public float ScaleFactor { get; }
@ -399,6 +402,56 @@ namespace Ryujinx.Graphics.Vulkan
return Info.Format == GAL.Format.D24UnormS8Uint && VkFormat == VkFormat.D32SfloatS8Uint; 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() public void Dispose()
{ {
if (_aliasedStorages != null) if (_aliasedStorages != null)