From 7838a45772a2746d251ae937a96165552a7ece39 Mon Sep 17 00:00:00 2001 From: gdk Date: Fri, 15 Apr 2022 21:22:19 -0300 Subject: [PATCH] Add barrier before use of some modified images --- Ryujinx.Graphics.GAL/IPipeline.cs | 3 +- .../Commands/SetTextureAndSamplerCommand.cs | 7 ++- .../Multithreading/ThreadedPipeline.cs | 5 +- .../Image/TextureBindingsManager.cs | 8 +-- Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | 14 +++-- .../Memory/BufferTextureBinding.cs | 17 +++++- Ryujinx.Graphics.OpenGL/Pipeline.cs | 2 +- .../DescriptorSetUpdater.cs | 8 ++- Ryujinx.Graphics.Vulkan/EnumConversion.cs | 23 ++++++++ Ryujinx.Graphics.Vulkan/FramebufferParams.cs | 22 ++++++++ Ryujinx.Graphics.Vulkan/HelperShader.cs | 4 +- Ryujinx.Graphics.Vulkan/PipelineBase.cs | 5 +- Ryujinx.Graphics.Vulkan/TextureStorage.cs | 53 +++++++++++++++++++ 13 files changed, 151 insertions(+), 20 deletions(-) diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs index c88cc7017..8e411f132 100644 --- a/Ryujinx.Graphics.GAL/IPipeline.cs +++ b/Ryujinx.Graphics.GAL/IPipeline.cs @@ -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 buffers); - void SetTextureAndSampler(int binding, ITexture texture, ISampler sampler); + void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler); void SetTransformFeedbackBuffers(ReadOnlySpan buffers); void SetUniformBuffers(int first, ReadOnlySpan buffers); diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureAndSamplerCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureAndSamplerCommand.cs index 27700278b..7ef58c3d0 100644 --- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureAndSamplerCommand.cs +++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureAndSamplerCommand.cs @@ -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 _texture; private TableRef _sampler; - public void Set(int binding, TableRef texture, TableRef sampler) + public void Set(ShaderStage stage, int binding, TableRef texture, TableRef 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(threaded)?.Base, command._sampler.GetAs(threaded)?.Base); + renderer.Pipeline.SetTextureAndSampler(command._stage, command._binding, command._texture.GetAs(threaded)?.Base, command._sampler.GetAs(threaded)?.Base); } } } diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs index a9f7c8e9d..9108de213 100644 --- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs +++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs @@ -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().Set(binding, Ref(texture), Ref(sampler)); + _renderer.New().Set(stage, binding, Ref(texture), Ref(sampler)); _renderer.QueueCommand(); } diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index 6f44dbb43..86eacdb46 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -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 { diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs index 7615d60d6..9f1f88b1e 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs @@ -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 /// /// Sets the buffer storage of a buffer texture. This will be bound when the buffer manager commits bindings. /// + /// Shader stage accessing the texture /// Buffer texture /// Address of the buffer in memory /// Size of the buffer in bytes /// Binding info for the buffer texture /// Format of the buffer texture /// Whether the binding is for an image or a sampler - 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)); } /// diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs b/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs index cf0d225e8..2a1408708 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs @@ -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 /// struct BufferTextureBinding { + /// + /// Shader stage accessing the texture. + /// + public ShaderStage Stage { get; } + /// /// The buffer texture. /// @@ -41,14 +47,23 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Create a new buffer texture binding. /// + /// Shader stage accessing the texture /// Buffer texture /// Base address /// Size in bytes /// Binding info /// Binding format /// Whether the binding is for an image or a sampler - 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; diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs index 02d4ab5cd..3ce4c141b 100644 --- a/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -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) { diff --git a/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs index aecc3bde3..94f4b9b6e 100644 --- a/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs +++ b/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs @@ -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() diff --git a/Ryujinx.Graphics.Vulkan/EnumConversion.cs b/Ryujinx.Graphics.Vulkan/EnumConversion.cs index 023051373..8a1422cbe 100644 --- a/Ryujinx.Graphics.Vulkan/EnumConversion.cs +++ b/Ryujinx.Graphics.Vulkan/EnumConversion.cs @@ -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) diff --git a/Ryujinx.Graphics.Vulkan/FramebufferParams.cs b/Ryujinx.Graphics.Vulkan/FramebufferParams.cs index e6b25ca85..06c0aec71 100644 --- a/Ryujinx.Graphics.Vulkan/FramebufferParams.cs +++ b/Ryujinx.Graphics.Vulkan/FramebufferParams.cs @@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.Vulkan { private readonly Device _device; private readonly Auto[] _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[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(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); + } } } diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs index 044c9da00..9615d8a48 100644 --- a/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -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 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 region = stackalloc float[RegionBufferSize / sizeof(float)]; diff --git a/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 0fc0d46ce..85a7f4791 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -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 buffers) diff --git a/Ryujinx.Graphics.Vulkan/TextureStorage.cs b/Ryujinx.Graphics.Vulkan/TextureStorage.cs index 21e16abed..60dc4d9b6 100644 --- a/Ryujinx.Graphics.Vulkan/TextureStorage.cs +++ b/Ryujinx.Graphics.Vulkan/TextureStorage.cs @@ -43,6 +43,9 @@ namespace Ryujinx.Graphics.Vulkan private Dictionary _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)