From 989709baf4d6d90615905af5221d1b963e008818 Mon Sep 17 00:00:00 2001 From: Gabriel A Date: Sat, 25 May 2024 18:05:49 -0300 Subject: [PATCH] Separate new commands, some PR feedback --- src/Ryujinx.Graphics.GAL/IPipeline.cs | 4 +- .../Multithreading/CommandHelper.cs | 2 + .../Multithreading/CommandType.cs | 2 + .../Commands/SetImageArrayCommand.cs | 22 +-- .../Commands/SetImageArraySeparateCommand.cs | 26 ++++ .../Commands/SetTextureArrayCommand.cs | 22 +-- .../SetTextureArraySeparateCommand.cs | 26 ++++ .../Multithreading/ThreadedPipeline.cs | 8 +- .../Image/TextureBindingsArrayCache.cs | 16 ++- .../Shader/ShaderInfoBuilder.cs | 72 +++++++--- src/Ryujinx.Graphics.OpenGL/Pipeline.cs | 4 +- src/Ryujinx.Graphics.Shader/SetBindingPair.cs | 39 +---- .../DescriptorSetUpdater.cs | 133 ++++++------------ src/Ryujinx.Graphics.Vulkan/ImageArray.cs | 22 ++- src/Ryujinx.Graphics.Vulkan/PipelineBase.cs | 14 +- src/Ryujinx.Graphics.Vulkan/TextureArray.cs | 22 ++- 16 files changed, 221 insertions(+), 213 deletions(-) create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArraySeparateCommand.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArraySeparateCommand.cs diff --git a/src/Ryujinx.Graphics.GAL/IPipeline.cs b/src/Ryujinx.Graphics.GAL/IPipeline.cs index 8f503c5079..cbf1bc3a22 100644 --- a/src/Ryujinx.Graphics.GAL/IPipeline.cs +++ b/src/Ryujinx.Graphics.GAL/IPipeline.cs @@ -60,7 +60,7 @@ namespace Ryujinx.Graphics.GAL void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat); void SetImageArray(ShaderStage stage, int binding, IImageArray array); - void SetImageArray(ShaderStage stage, int setIndex, int binding, IImageArray array); + void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array); void SetLineParameters(float width, bool smooth); @@ -92,7 +92,7 @@ namespace Ryujinx.Graphics.GAL void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler); void SetTextureArray(ShaderStage stage, int binding, ITextureArray array); - void SetTextureArray(ShaderStage stage, int setIndex, int binding, ITextureArray array); + void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array); void SetTransformFeedbackBuffers(ReadOnlySpan buffers); void SetUniformBuffers(ReadOnlySpan buffers); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs b/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs index 23f1a64ef9..edaae3042d 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs @@ -124,6 +124,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading Register(CommandType.SetUniformBuffers); Register(CommandType.SetImage); Register(CommandType.SetImageArray); + Register(CommandType.SetImageArraySeparate); Register(CommandType.SetIndexBuffer); Register(CommandType.SetLineParameters); Register(CommandType.SetLogicOpState); @@ -141,6 +142,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading Register(CommandType.SetStencilTest); Register(CommandType.SetTextureAndSampler); Register(CommandType.SetTextureArray); + Register(CommandType.SetTextureArraySeparate); Register(CommandType.SetUserClipDistance); Register(CommandType.SetVertexAttribs); Register(CommandType.SetVertexBuffers); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs b/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs index f95aab05b4..7586953526 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs @@ -84,6 +84,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading SetUniformBuffers, SetImage, SetImageArray, + SetImageArraySeparate, SetIndexBuffer, SetLineParameters, SetLogicOpState, @@ -101,6 +102,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading SetStencilTest, SetTextureAndSampler, SetTextureArray, + SetTextureArraySeparate, SetUserClipDistance, SetVertexAttribs, SetVertexBuffers, diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArrayCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArrayCommand.cs index 64436eaee0..b8d3c7ac5c 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArrayCommand.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArrayCommand.cs @@ -8,39 +8,19 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands { public readonly CommandType CommandType => CommandType.SetImageArray; private ShaderStage _stage; - private bool _hasSetIndex; - private int _setIndex; private int _binding; private TableRef _array; public void Set(ShaderStage stage, int binding, TableRef array) { _stage = stage; - _hasSetIndex = false; - _setIndex = 0; - _binding = binding; - _array = array; - } - - public void Set(ShaderStage stage, int setIndex, int binding, TableRef array) - { - _stage = stage; - _hasSetIndex = true; - _setIndex = setIndex; _binding = binding; _array = array; } public static void Run(ref SetImageArrayCommand command, ThreadedRenderer threaded, IRenderer renderer) { - if (command._hasSetIndex) - { - renderer.Pipeline.SetImageArray(command._stage, command._setIndex, command._binding, command._array.GetAs(threaded)?.Base); - } - else - { - renderer.Pipeline.SetImageArray(command._stage, command._binding, command._array.GetAs(threaded)?.Base); - } + renderer.Pipeline.SetImageArray(command._stage, command._binding, command._array.GetAs(threaded)?.Base); } } } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArraySeparateCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArraySeparateCommand.cs new file mode 100644 index 0000000000..abeb58a06f --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageArraySeparateCommand.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; +using Ryujinx.Graphics.Shader; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands +{ + struct SetImageArraySeparateCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.SetImageArraySeparate; + private ShaderStage _stage; + private int _setIndex; + private TableRef _array; + + public void Set(ShaderStage stage, int setIndex, TableRef array) + { + _stage = stage; + _setIndex = setIndex; + _array = array; + } + + public static void Run(ref SetImageArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + renderer.Pipeline.SetImageArraySeparate(command._stage, command._setIndex, command._array.GetAs(threaded)?.Base); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArrayCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArrayCommand.cs index 4b96b749b2..45e28aa658 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArrayCommand.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArrayCommand.cs @@ -8,39 +8,19 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands { public readonly CommandType CommandType => CommandType.SetTextureArray; private ShaderStage _stage; - private bool _hasSetIndex; - private int _setIndex; private int _binding; private TableRef _array; public void Set(ShaderStage stage, int binding, TableRef array) { _stage = stage; - _hasSetIndex = false; - _setIndex = 0; - _binding = binding; - _array = array; - } - - public void Set(ShaderStage stage, int setIndex, int binding, TableRef array) - { - _stage = stage; - _hasSetIndex = true; - _setIndex = setIndex; _binding = binding; _array = array; } public static void Run(ref SetTextureArrayCommand command, ThreadedRenderer threaded, IRenderer renderer) { - if (command._hasSetIndex) - { - renderer.Pipeline.SetTextureArray(command._stage, command._setIndex, command._binding, command._array.GetAs(threaded)?.Base); - } - else - { - renderer.Pipeline.SetTextureArray(command._stage, command._binding, command._array.GetAs(threaded)?.Base); - } + renderer.Pipeline.SetTextureArray(command._stage, command._binding, command._array.GetAs(threaded)?.Base); } } } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArraySeparateCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArraySeparateCommand.cs new file mode 100644 index 0000000000..b179f2e70a --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureArraySeparateCommand.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; +using Ryujinx.Graphics.Shader; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands +{ + struct SetTextureArraySeparateCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.SetTextureArraySeparate; + private ShaderStage _stage; + private int _setIndex; + private TableRef _array; + + public void Set(ShaderStage stage, int setIndex, TableRef array) + { + _stage = stage; + _setIndex = setIndex; + _array = array; + } + + public static void Run(ref SetTextureArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer) + { + renderer.Pipeline.SetTextureArraySeparate(command._stage, command._setIndex, command._array.GetAs(threaded)?.Base); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs index 78f078e6c4..edd79d8a07 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs @@ -189,9 +189,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading _renderer.QueueCommand(); } - public void SetImageArray(ShaderStage stage, int setIndex, int binding, IImageArray array) + public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) { - _renderer.New().Set(stage, setIndex, binding, Ref(array)); + _renderer.New().Set(stage, setIndex, Ref(array)); _renderer.QueueCommand(); } @@ -303,9 +303,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading _renderer.QueueCommand(); } - public void SetTextureArray(ShaderStage stage, int setIndex, int binding, ITextureArray array) + public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) { - _renderer.New().Set(stage, setIndex, binding, Ref(array)); + _renderer.New().Set(stage, setIndex, Ref(array)); _renderer.QueueCommand(); } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs index 022eb3e976..a560a238b1 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs @@ -961,11 +961,17 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Updates a texture array binding on the host. + /// + /// Shader stage where the array is used + /// Array binding information + /// Texture array private void SetTextureArray(ShaderStage stage, in TextureBindingInfo bindingInfo, ITextureArray array) { if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex) { - _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Set, bindingInfo.Binding, array); + _context.Renderer.Pipeline.SetTextureArraySeparate(stage, bindingInfo.Set, array); } else { @@ -973,11 +979,17 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Updates a image array binding on the host. + /// + /// Shader stage where the array is used + /// Array binding information + /// Image array private void SetImageArray(ShaderStage stage, in TextureBindingInfo bindingInfo, IImageArray array) { if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex) { - _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Set, bindingInfo.Binding, array); + _context.Renderer.Pipeline.SetImageArraySeparate(stage, bindingInfo.Set, array); } else { diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs index 7cc607ee6d..42b2cbb59b 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs @@ -10,13 +10,6 @@ namespace Ryujinx.Graphics.Gpu.Shader /// class ShaderInfoBuilder { - private const int TotalSets = 4; - - private const int UniformSetIndex = 0; - private const int StorageSetIndex = 1; - private const int TextureSetIndex = 2; - private const int ImageSetIndex = 3; - private const ResourceStages SupportBufferStages = ResourceStages.Compute | ResourceStages.Vertex | @@ -52,17 +45,27 @@ namespace Ryujinx.Graphics.Gpu.Shader _fragmentOutputMap = -1; - _resourceDescriptors = new List[TotalSets]; - _resourceUsages = new List[TotalSets]; + int uniformSetIndex = context.Capabilities.UniformBufferSetIndex; + int storageSetIndex = context.Capabilities.StorageBufferSetIndex; + int textureSetIndex = context.Capabilities.TextureSetIndex; + int imageSetIndex = context.Capabilities.ImageSetIndex; - for (int index = 0; index < TotalSets; index++) + int totalSets = Math.Max(uniformSetIndex, storageSetIndex); + totalSets = Math.Max(totalSets, textureSetIndex); + totalSets = Math.Max(totalSets, imageSetIndex); + totalSets++; + + _resourceDescriptors = new List[totalSets]; + _resourceUsages = new List[totalSets]; + + for (int index = 0; index < totalSets; index++) { _resourceDescriptors[index] = new(); _resourceUsages[index] = new(); } - AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1); - AddUsage(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1); + AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1); + AddUsage(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1); ResourceReservationCounts rrc = new(!context.Capabilities.SupportsTransformFeedback && tfEnabled, vertexAsCompute); @@ -74,12 +77,20 @@ namespace Ryujinx.Graphics.Gpu.Shader // TODO: Handle that better? Maybe we should only set the binding that are really needed on each shader. ResourceStages stages = vertexAsCompute ? ResourceStages.Compute | ResourceStages.Vertex : VtgStages; - PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, UniformSetIndex, 1, rrc.ReservedConstantBuffers - 1); - PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, StorageSetIndex, 0, rrc.ReservedStorageBuffers); - PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, TextureSetIndex, 0, rrc.ReservedTextures); - PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, ImageSetIndex, 0, rrc.ReservedImages); + PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, uniformSetIndex, 1, rrc.ReservedConstantBuffers - 1); + PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, storageSetIndex, 0, rrc.ReservedStorageBuffers); + PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, textureSetIndex, 0, rrc.ReservedTextures); + PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, imageSetIndex, 0, rrc.ReservedImages); } + /// + /// Populates descriptors and usages for vertex as compute and transform feedback emulation reserved resources. + /// + /// Shader stages where the resources are used + /// Resource type + /// Resource set index where the resources are used + /// First binding number + /// Amount of bindings private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count) { AddDescriptor(stages, type, setIndex, start, count); @@ -128,10 +139,15 @@ namespace Ryujinx.Graphics.Gpu.Shader int textureBinding = _reservedTextures + stageIndex * texturesPerStage * 2; int imageBinding = _reservedImages + stageIndex * imagesPerStage * 2; - AddDescriptor(stages, ResourceType.UniformBuffer, UniformSetIndex, uniformBinding, uniformsPerStage); - AddDescriptor(stages, ResourceType.StorageBuffer, StorageSetIndex, storageBinding, storagesPerStage); - AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, TextureSetIndex, textureBinding, texturesPerStage); - AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, ImageSetIndex, imageBinding, imagesPerStage); + int uniformSetIndex = _context.Capabilities.UniformBufferSetIndex; + int storageSetIndex = _context.Capabilities.StorageBufferSetIndex; + int textureSetIndex = _context.Capabilities.TextureSetIndex; + int imageSetIndex = _context.Capabilities.ImageSetIndex; + + AddDescriptor(stages, ResourceType.UniformBuffer, uniformSetIndex, uniformBinding, uniformsPerStage); + AddDescriptor(stages, ResourceType.StorageBuffer, storageSetIndex, storageBinding, storagesPerStage); + AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, textureSetIndex, textureBinding, texturesPerStage); + AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, imageSetIndex, imageBinding, imagesPerStage); AddArrayDescriptors(info.Textures, stages, isImage: false); AddArrayDescriptors(info.Images, stages, isImage: true); @@ -242,6 +258,11 @@ namespace Ryujinx.Graphics.Gpu.Shader } } + /// + /// Gets the list of resource descriptors for a given set index. A new list will be created if needed. + /// + /// Resource set index + /// List of resource descriptors private List GetDescriptors(int setIndex) { if (_resourceDescriptors.Length <= setIndex) @@ -258,6 +279,11 @@ namespace Ryujinx.Graphics.Gpu.Shader return _resourceDescriptors[setIndex]; } + /// + /// Gets the list of resource usages for a given set index. A new list will be created if needed. + /// + /// Resource set index + /// List of resource usages private List GetUsages(int setIndex) { if (_resourceUsages.Length <= setIndex) @@ -274,6 +300,12 @@ namespace Ryujinx.Graphics.Gpu.Shader return _resourceUsages[setIndex]; } + /// + /// Gets a resource type from a texture descriptor. + /// + /// Texture descriptor + /// Whether the texture is a image texture (writable) or not (sampled) + /// Resource type private static ResourceType GetTextureResourceType(TextureDescriptor texture, bool isImage) { bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer; diff --git a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs index 1f067515bf..54f6b3f7b2 100644 --- a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -963,7 +963,7 @@ namespace Ryujinx.Graphics.OpenGL (array as ImageArray).Bind(binding); } - public void SetImageArray(ShaderStage stage, int setIndex, int binding, IImageArray array) + public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) { throw new NotSupportedException("OpenGL does not support descriptor sets."); } @@ -1317,7 +1317,7 @@ namespace Ryujinx.Graphics.OpenGL (array as TextureArray).Bind(binding); } - public void SetTextureArray(ShaderStage stage, int setIndex, int binding, ITextureArray array) + public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) { throw new NotSupportedException("OpenGL does not support descriptor sets."); } diff --git a/src/Ryujinx.Graphics.Shader/SetBindingPair.cs b/src/Ryujinx.Graphics.Shader/SetBindingPair.cs index 152d68334c..1e8a4f9c61 100644 --- a/src/Ryujinx.Graphics.Shader/SetBindingPair.cs +++ b/src/Ryujinx.Graphics.Shader/SetBindingPair.cs @@ -1,41 +1,4 @@ -using System; - namespace Ryujinx.Graphics.Shader { - public readonly struct SetBindingPair : IEquatable - { - public readonly int SetIndex; - public readonly int Binding; - - public SetBindingPair(int setIndex, int binding) - { - SetIndex = setIndex; - Binding = binding; - } - - public override bool Equals(object obj) - { - return obj is SetBindingPair other && Equals(other); - } - - public bool Equals(SetBindingPair other) - { - return SetIndex == other.SetIndex && Binding == other.Binding; - } - - public override int GetHashCode() - { - return (((ulong)(uint)SetIndex << 32) | (uint)Binding).GetHashCode(); - } - - public static bool operator ==(SetBindingPair left, SetBindingPair right) - { - return left.Equals(right); - } - - public static bool operator !=(SetBindingPair left, SetBindingPair right) - { - return !(left == right); - } - } + public readonly record struct SetBindingPair(int SetIndex, int Binding); } diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs index d0afb9b0ab..bfe3cd7ada 100644 --- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs @@ -69,31 +69,7 @@ namespace Ryujinx.Graphics.Vulkan } } - private record struct ArrayRef - { - public ShaderStage Stage; - public T Array; - - public ArrayRef(ShaderStage stage, T array) - { - Stage = stage; - Array = array; - } - } - - private record struct ArrayExtraRef - { - public ShaderStage Stage; - public T Array; - public int Binding; - - public ArrayExtraRef(ShaderStage stage, T array, int binding) - { - Stage = stage; - Array = array; - Binding = binding; - } - } + private readonly record struct ArrayRef(ShaderStage Stage, T Array); private readonly VulkanRenderer _gd; private readonly Device _device; @@ -111,8 +87,8 @@ namespace Ryujinx.Graphics.Vulkan private ArrayRef[] _textureArrayRefs; private ArrayRef[] _imageArrayRefs; - private ArrayExtraRef[] _textureArrayExtraRefs; - private ArrayExtraRef[] _imageArrayExtraRefs; + private ArrayRef[] _textureArrayExtraRefs; + private ArrayRef[] _imageArrayExtraRefs; private readonly DescriptorBufferInfo[] _uniformBuffers; private readonly DescriptorBufferInfo[] _storageBuffers; @@ -169,8 +145,8 @@ namespace Ryujinx.Graphics.Vulkan _textureArrayRefs = Array.Empty>(); _imageArrayRefs = Array.Empty>(); - _textureArrayExtraRefs = Array.Empty>(); - _imageArrayExtraRefs = Array.Empty>(); + _textureArrayExtraRefs = Array.Empty>(); + _imageArrayExtraRefs = Array.Empty>(); _uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings]; _storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings]; @@ -515,48 +491,39 @@ namespace Ryujinx.Graphics.Vulkan public void SetTextureArray(CommandBufferScoped cbs, ShaderStage stage, int binding, ITextureArray array) { - if (_textureArrayRefs.Length <= binding) - { - Array.Resize(ref _textureArrayRefs, binding + ArrayGrowthSize); - } + ref ArrayRef arrayRef = ref GetArrayRef(ref _textureArrayRefs, binding, ArrayGrowthSize); - if (_textureArrayRefs[binding].Stage != stage || _textureArrayRefs[binding].Array != array) + if (arrayRef.Stage != stage || arrayRef.Array != array) { - if (_textureArrayRefs[binding].Array != null) - { - _textureArrayRefs[binding].Array.Bound = false; - } + arrayRef.Array?.DecrementBindCount(); if (array is TextureArray textureArray) { - textureArray.Bound = true; + textureArray.IncrementBindCount(); textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags()); } - _textureArrayRefs[binding] = new ArrayRef(stage, array as TextureArray); + arrayRef = new ArrayRef(stage, array as TextureArray); SignalDirty(DirtyFlags.Texture); } } - public void SetTextureArray(CommandBufferScoped cbs, ShaderStage stage, int setIndex, int binding, ITextureArray array) + public void SetTextureArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, ITextureArray array) { - ref ArrayExtraRef arrayRef = ref GetExtraArrayRef(ref _textureArrayExtraRefs, setIndex, binding); + ref ArrayRef arrayRef = ref GetArrayRef(ref _textureArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts); if (arrayRef.Stage != stage || arrayRef.Array != array) { - if (arrayRef.Array != null) - { - arrayRef.Array.Bound = false; - } + arrayRef.Array?.DecrementBindCount(); if (array is TextureArray textureArray) { - textureArray.Bound = true; + textureArray.IncrementBindCount(); textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags()); } - arrayRef = new ArrayExtraRef(stage, array as TextureArray, binding); + arrayRef = new ArrayRef(stage, array as TextureArray); SignalDirty(DirtyFlags.Texture); } @@ -564,66 +531,54 @@ namespace Ryujinx.Graphics.Vulkan public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int binding, IImageArray array) { - if (_imageArrayRefs.Length <= binding) - { - Array.Resize(ref _imageArrayRefs, binding + ArrayGrowthSize); - } - - if (_imageArrayRefs[binding].Stage != stage || _imageArrayRefs[binding].Array != array) - { - if (_imageArrayRefs[binding].Array != null) - { - _imageArrayRefs[binding].Array.Bound = false; - } - - if (array is ImageArray imageArray) - { - imageArray.Bound = true; - imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags()); - } - - _imageArrayRefs[binding] = new ArrayRef(stage, array as ImageArray); - - SignalDirty(DirtyFlags.Image); - } - } - - public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int setIndex, int binding, IImageArray array) - { - ref ArrayExtraRef arrayRef = ref GetExtraArrayRef(ref _imageArrayExtraRefs, setIndex, binding); + ref ArrayRef arrayRef = ref GetArrayRef(ref _imageArrayRefs, binding, ArrayGrowthSize); if (arrayRef.Stage != stage || arrayRef.Array != array) { - if (arrayRef.Array != null) - { - arrayRef.Array.Bound = false; - } + arrayRef.Array?.DecrementBindCount(); if (array is ImageArray imageArray) { - imageArray.Bound = true; + imageArray.IncrementBindCount(); imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags()); } - arrayRef = new ArrayExtraRef(stage, array as ImageArray, binding); + arrayRef = new ArrayRef(stage, array as ImageArray); SignalDirty(DirtyFlags.Image); } } - private static ref ArrayExtraRef GetExtraArrayRef(ref ArrayExtraRef[] array, int setIndex, int binding) + public void SetImageArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, IImageArray array) { - setIndex -= PipelineBase.DescriptorSetLayouts; + ref ArrayRef arrayRef = ref GetArrayRef(ref _imageArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts); - ArgumentOutOfRangeException.ThrowIfNegative(setIndex); - ArgumentOutOfRangeException.ThrowIfNegative(binding); - - if (array.Length <= setIndex) + if (arrayRef.Stage != stage || arrayRef.Array != array) { - Array.Resize(ref array, setIndex + 1); + arrayRef.Array?.DecrementBindCount(); + + if (array is ImageArray imageArray) + { + imageArray.IncrementBindCount(); + imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags()); + } + + arrayRef = new ArrayRef(stage, array as ImageArray); + + SignalDirty(DirtyFlags.Image); + } + } + + private static ref ArrayRef GetArrayRef(ref ArrayRef[] array, int index, int growthSize = 1) + { + ArgumentOutOfRangeException.ThrowIfNegative(index); + + if (array.Length <= index) + { + Array.Resize(ref array, index + growthSize); } - return ref array[setIndex]; + return ref array[index]; } public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan buffers) diff --git a/src/Ryujinx.Graphics.Vulkan/ImageArray.cs b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs index 24499d3534..72c007fca1 100644 --- a/src/Ryujinx.Graphics.Vulkan/ImageArray.cs +++ b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Vulkan private readonly bool _isBuffer; - public bool Bound; + private int _bindCount; public ImageArray(VulkanRenderer gd, int size, bool isBuffer) { @@ -101,7 +101,10 @@ namespace Ryujinx.Graphics.Vulkan _storages = null; _cachedDescriptorSets = null; - _gd.PipelineInternal.ForceImageDirty(); + if (_bindCount != 0) + { + _gd.PipelineInternal.ForceImageDirty(); + } } public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags) @@ -225,5 +228,20 @@ namespace Ryujinx.Graphics.Vulkan return sets; } + + public void IncrementBindCount() + { + _bindCount++; + } + + public void DecrementBindCount() + { + int newBindCount = --_bindCount; + + if (newBindCount < 0) + { + throw new Exception("huh?"); + } + } } } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index bbb8a4c9c3..918de59b73 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -751,14 +751,12 @@ namespace Ryujinx.Graphics.Vulkan _vertexBufferUpdater.Commit(Cbs); } -#pragma warning disable CA1822 // Mark member as static public void SetAlphaTest(bool enable, float reference, CompareOp op) { // This is currently handled using shader specialization, as Vulkan does not support alpha test. // In the future, we may want to use this to write the reference value into the support buffer, // to avoid creating one version of the shader per reference value used. } -#pragma warning restore CA1822 public void SetBlendState(AdvancedBlendDescriptor blend) { @@ -903,9 +901,9 @@ namespace Ryujinx.Graphics.Vulkan _descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array); } - public void SetImageArray(ShaderStage stage, int setIndex, int binding, IImageArray array) + public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) { - _descriptorSetUpdater.SetImageArray(Cbs, stage, setIndex, binding, array); + _descriptorSetUpdater.SetImageArraySeparate(Cbs, stage, setIndex, array); } public void SetIndexBuffer(BufferRange buffer, IndexType type) @@ -950,7 +948,6 @@ namespace Ryujinx.Graphics.Vulkan // TODO: Default levels (likely needs emulation on shaders?) } -#pragma warning disable CA1822 // Mark member as static public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin) { // TODO. @@ -960,7 +957,6 @@ namespace Ryujinx.Graphics.Vulkan { // TODO. } -#pragma warning restore CA1822 public void SetPrimitiveRestart(bool enable, int index) { @@ -1161,9 +1157,9 @@ namespace Ryujinx.Graphics.Vulkan _descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array); } - public void SetTextureArray(ShaderStage stage, int setIndex, int binding, ITextureArray array) + public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) { - _descriptorSetUpdater.SetTextureArray(Cbs, stage, setIndex, binding, array); + _descriptorSetUpdater.SetTextureArraySeparate(Cbs, stage, setIndex, array); } public void SetTransformFeedbackBuffers(ReadOnlySpan buffers) @@ -1196,12 +1192,10 @@ namespace Ryujinx.Graphics.Vulkan _descriptorSetUpdater.SetUniformBuffers(CommandBuffer, buffers); } -#pragma warning disable CA1822 // Mark member as static public void SetUserClipDistance(int index, bool enableClip) { // TODO. } -#pragma warning restore CA1822 public void SetVertexAttribs(ReadOnlySpan vertexAttribs) { diff --git a/src/Ryujinx.Graphics.Vulkan/TextureArray.cs b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs index c75cc2035b..6e1f1b31a5 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureArray.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Vulkan private readonly bool _isBuffer; - public bool Bound; + private int _bindCount; public TextureArray(VulkanRenderer gd, int size, bool isBuffer) { @@ -110,7 +110,10 @@ namespace Ryujinx.Graphics.Vulkan _storages = null; _cachedDescriptorSets = null; - _gd.PipelineInternal.ForceTextureDirty(); + if (_bindCount != 0) + { + _gd.PipelineInternal.ForceTextureDirty(); + } } public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags) @@ -241,5 +244,20 @@ namespace Ryujinx.Graphics.Vulkan return sets; } + + public void IncrementBindCount() + { + _bindCount++; + } + + public void DecrementBindCount() + { + int newBindCount = --_bindCount; + + if (newBindCount < 0) + { + throw new Exception("huh?"); + } + } } }