mirror of
				https://github.com/ryujinx-mirror/ryujinx.git
				synced 2025-11-04 08:59:04 -06:00 
			
		
		
		
	Allow texture arrays to use separate descriptor sets on Vulkan (#6870)
* Report base and extra sets from the backend * Pass texture set index everywhere * Key textures using set and binding (rather than just binding) * Start using extra sets for array textures * Shader cache version bump * Separate new commands, some PR feedback * Introduce new manual descriptor set reservation method that prevents it from being used by something else while owned by an array * Move bind extra sets logic to new method * Should only use separate array is MaximumExtraSets is not zero * Format whitespace
This commit is contained in:
		@@ -51,6 +51,13 @@ namespace Ryujinx.Graphics.GAL
 | 
			
		||||
        public readonly bool SupportsIndirectParameters;
 | 
			
		||||
        public readonly bool SupportsDepthClipControl;
 | 
			
		||||
 | 
			
		||||
        public readonly int UniformBufferSetIndex;
 | 
			
		||||
        public readonly int StorageBufferSetIndex;
 | 
			
		||||
        public readonly int TextureSetIndex;
 | 
			
		||||
        public readonly int ImageSetIndex;
 | 
			
		||||
        public readonly int ExtraSetBaseIndex;
 | 
			
		||||
        public readonly int MaximumExtraSets;
 | 
			
		||||
 | 
			
		||||
        public readonly uint MaximumUniformBuffersPerStage;
 | 
			
		||||
        public readonly uint MaximumStorageBuffersPerStage;
 | 
			
		||||
        public readonly uint MaximumTexturesPerStage;
 | 
			
		||||
@@ -109,6 +116,12 @@ namespace Ryujinx.Graphics.GAL
 | 
			
		||||
            bool supportsViewportSwizzle,
 | 
			
		||||
            bool supportsIndirectParameters,
 | 
			
		||||
            bool supportsDepthClipControl,
 | 
			
		||||
            int uniformBufferSetIndex,
 | 
			
		||||
            int storageBufferSetIndex,
 | 
			
		||||
            int textureSetIndex,
 | 
			
		||||
            int imageSetIndex,
 | 
			
		||||
            int extraSetBaseIndex,
 | 
			
		||||
            int maximumExtraSets,
 | 
			
		||||
            uint maximumUniformBuffersPerStage,
 | 
			
		||||
            uint maximumStorageBuffersPerStage,
 | 
			
		||||
            uint maximumTexturesPerStage,
 | 
			
		||||
@@ -164,6 +177,12 @@ namespace Ryujinx.Graphics.GAL
 | 
			
		||||
            SupportsViewportSwizzle = supportsViewportSwizzle;
 | 
			
		||||
            SupportsIndirectParameters = supportsIndirectParameters;
 | 
			
		||||
            SupportsDepthClipControl = supportsDepthClipControl;
 | 
			
		||||
            UniformBufferSetIndex = uniformBufferSetIndex;
 | 
			
		||||
            StorageBufferSetIndex = storageBufferSetIndex;
 | 
			
		||||
            TextureSetIndex = textureSetIndex;
 | 
			
		||||
            ImageSetIndex = imageSetIndex;
 | 
			
		||||
            ExtraSetBaseIndex = extraSetBaseIndex;
 | 
			
		||||
            MaximumExtraSets = maximumExtraSets;
 | 
			
		||||
            MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
 | 
			
		||||
            MaximumStorageBuffersPerStage = maximumStorageBuffersPerStage;
 | 
			
		||||
            MaximumTexturesPerStage = maximumTexturesPerStage;
 | 
			
		||||
 
 | 
			
		||||
@@ -60,6 +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 SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array);
 | 
			
		||||
 | 
			
		||||
        void SetLineParameters(float width, bool smooth);
 | 
			
		||||
 | 
			
		||||
@@ -91,6 +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 SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array);
 | 
			
		||||
 | 
			
		||||
        void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
 | 
			
		||||
        void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);
 | 
			
		||||
 
 | 
			
		||||
@@ -124,6 +124,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
 | 
			
		||||
            Register<SetUniformBuffersCommand>(CommandType.SetUniformBuffers);
 | 
			
		||||
            Register<SetImageCommand>(CommandType.SetImage);
 | 
			
		||||
            Register<SetImageArrayCommand>(CommandType.SetImageArray);
 | 
			
		||||
            Register<SetImageArraySeparateCommand>(CommandType.SetImageArraySeparate);
 | 
			
		||||
            Register<SetIndexBufferCommand>(CommandType.SetIndexBuffer);
 | 
			
		||||
            Register<SetLineParametersCommand>(CommandType.SetLineParameters);
 | 
			
		||||
            Register<SetLogicOpStateCommand>(CommandType.SetLogicOpState);
 | 
			
		||||
@@ -141,6 +142,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
 | 
			
		||||
            Register<SetStencilTestCommand>(CommandType.SetStencilTest);
 | 
			
		||||
            Register<SetTextureAndSamplerCommand>(CommandType.SetTextureAndSampler);
 | 
			
		||||
            Register<SetTextureArrayCommand>(CommandType.SetTextureArray);
 | 
			
		||||
            Register<SetTextureArraySeparateCommand>(CommandType.SetTextureArraySeparate);
 | 
			
		||||
            Register<SetUserClipDistanceCommand>(CommandType.SetUserClipDistance);
 | 
			
		||||
            Register<SetVertexAttribsCommand>(CommandType.SetVertexAttribs);
 | 
			
		||||
            Register<SetVertexBuffersCommand>(CommandType.SetVertexBuffers);
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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<SetImageArraySeparateCommand>
 | 
			
		||||
    {
 | 
			
		||||
        public readonly CommandType CommandType => CommandType.SetImageArraySeparate;
 | 
			
		||||
        private ShaderStage _stage;
 | 
			
		||||
        private int _setIndex;
 | 
			
		||||
        private TableRef<IImageArray> _array;
 | 
			
		||||
 | 
			
		||||
        public void Set(ShaderStage stage, int setIndex, TableRef<IImageArray> 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<ThreadedImageArray>(threaded)?.Base);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<SetTextureArraySeparateCommand>
 | 
			
		||||
    {
 | 
			
		||||
        public readonly CommandType CommandType => CommandType.SetTextureArraySeparate;
 | 
			
		||||
        private ShaderStage _stage;
 | 
			
		||||
        private int _setIndex;
 | 
			
		||||
        private TableRef<ITextureArray> _array;
 | 
			
		||||
 | 
			
		||||
        public void Set(ShaderStage stage, int setIndex, TableRef<ITextureArray> 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<ThreadedTextureArray>(threaded)?.Base);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -189,6 +189,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
 | 
			
		||||
            _renderer.QueueCommand();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
 | 
			
		||||
        {
 | 
			
		||||
            _renderer.New<SetImageArraySeparateCommand>().Set(stage, setIndex, Ref(array));
 | 
			
		||||
            _renderer.QueueCommand();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetIndexBuffer(BufferRange buffer, IndexType type)
 | 
			
		||||
        {
 | 
			
		||||
            _renderer.New<SetIndexBufferCommand>().Set(buffer, type);
 | 
			
		||||
@@ -297,6 +303,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
 | 
			
		||||
            _renderer.QueueCommand();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
 | 
			
		||||
        {
 | 
			
		||||
            _renderer.New<SetTextureArraySeparateCommand>().Set(stage, setIndex, Ref(array));
 | 
			
		||||
            _renderer.QueueCommand();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
 | 
			
		||||
        {
 | 
			
		||||
            _renderer.New<SetTransformFeedbackBuffersCommand>().Set(_renderer.CopySpan(buffers));
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public Format Format { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Shader texture host set index.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int Set { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Shader texture host binding point.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -54,15 +59,17 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="target">The shader sampler target type</param>
 | 
			
		||||
        /// <param name="format">Format of the image as declared on the shader</param>
 | 
			
		||||
        /// <param name="set">Shader texture host set index</param>
 | 
			
		||||
        /// <param name="binding">The shader texture binding point</param>
 | 
			
		||||
        /// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
 | 
			
		||||
        /// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
 | 
			
		||||
        /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
 | 
			
		||||
        /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
 | 
			
		||||
        public TextureBindingInfo(Target target, Format format, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
 | 
			
		||||
        public TextureBindingInfo(Target target, Format format, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
 | 
			
		||||
        {
 | 
			
		||||
            Target = target;
 | 
			
		||||
            Format = format;
 | 
			
		||||
            Set = set;
 | 
			
		||||
            Binding = binding;
 | 
			
		||||
            ArrayLength = arrayLength;
 | 
			
		||||
            CbufSlot = cbufSlot;
 | 
			
		||||
@@ -74,6 +81,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// Constructs the texture binding information structure.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="target">The shader sampler target type</param>
 | 
			
		||||
        /// <param name="set">Shader texture host set index</param>
 | 
			
		||||
        /// <param name="binding">The shader texture binding point</param>
 | 
			
		||||
        /// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
 | 
			
		||||
        /// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
 | 
			
		||||
@@ -82,12 +90,13 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// <param name="isSamplerOnly">Indicates that the binding is for a sampler</param>
 | 
			
		||||
        public TextureBindingInfo(
 | 
			
		||||
            Target target,
 | 
			
		||||
            int set,
 | 
			
		||||
            int binding,
 | 
			
		||||
            int arrayLength,
 | 
			
		||||
            int cbufSlot,
 | 
			
		||||
            int handle,
 | 
			
		||||
            TextureUsageFlags flags,
 | 
			
		||||
            bool isSamplerOnly) : this(target, 0, binding, arrayLength, cbufSlot, handle, flags)
 | 
			
		||||
            bool isSamplerOnly) : this(target, 0, set, binding, arrayLength, cbufSlot, handle, flags)
 | 
			
		||||
        {
 | 
			
		||||
            IsSamplerOnly = isSamplerOnly;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -566,7 +566,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
            int stageIndex,
 | 
			
		||||
            int textureBufferIndex,
 | 
			
		||||
            SamplerIndex samplerIndex,
 | 
			
		||||
            TextureBindingInfo bindingInfo)
 | 
			
		||||
            in TextureBindingInfo bindingInfo)
 | 
			
		||||
        {
 | 
			
		||||
            Update(texturePool, samplerPool, stage, stageIndex, textureBufferIndex, isImage: false, samplerIndex, bindingInfo);
 | 
			
		||||
        }
 | 
			
		||||
@@ -579,7 +579,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// <param name="stageIndex">Shader stage index where the array is used</param>
 | 
			
		||||
        /// <param name="textureBufferIndex">Texture constant buffer index</param>
 | 
			
		||||
        /// <param name="bindingInfo">Array binding information</param>
 | 
			
		||||
        public void UpdateImageArray(TexturePool texturePool, ShaderStage stage, int stageIndex, int textureBufferIndex, TextureBindingInfo bindingInfo)
 | 
			
		||||
        public void UpdateImageArray(TexturePool texturePool, ShaderStage stage, int stageIndex, int textureBufferIndex, in TextureBindingInfo bindingInfo)
 | 
			
		||||
        {
 | 
			
		||||
            Update(texturePool, null, stage, stageIndex, textureBufferIndex, isImage: true, SamplerIndex.ViaHeaderIndex, bindingInfo);
 | 
			
		||||
        }
 | 
			
		||||
@@ -603,7 +603,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
            int textureBufferIndex,
 | 
			
		||||
            bool isImage,
 | 
			
		||||
            SamplerIndex samplerIndex,
 | 
			
		||||
            TextureBindingInfo bindingInfo)
 | 
			
		||||
            in TextureBindingInfo bindingInfo)
 | 
			
		||||
        {
 | 
			
		||||
            if (IsDirectHandleType(bindingInfo.Handle))
 | 
			
		||||
            {
 | 
			
		||||
@@ -623,7 +623,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// <param name="stage">Shader stage where the array is used</param>
 | 
			
		||||
        /// <param name="isImage">Whether the array is a image or texture array</param>
 | 
			
		||||
        /// <param name="bindingInfo">Array binding information</param>
 | 
			
		||||
        private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, TextureBindingInfo bindingInfo)
 | 
			
		||||
        private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, in TextureBindingInfo bindingInfo)
 | 
			
		||||
        {
 | 
			
		||||
            CacheEntry entry = GetOrAddEntry(texturePool, samplerPool, bindingInfo, isImage, out bool isNewEntry);
 | 
			
		||||
 | 
			
		||||
@@ -638,11 +638,11 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
 | 
			
		||||
                if (isImage)
 | 
			
		||||
                {
 | 
			
		||||
                    _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
 | 
			
		||||
                    SetImageArray(stage, bindingInfo, entry.ImageArray);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
 | 
			
		||||
                    SetTextureArray(stage, bindingInfo, entry.TextureArray);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
@@ -737,14 +737,14 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                entry.ImageArray.SetFormats(0, formats);
 | 
			
		||||
                entry.ImageArray.SetImages(0, textures);
 | 
			
		||||
 | 
			
		||||
                _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
 | 
			
		||||
                SetImageArray(stage, bindingInfo, entry.ImageArray);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                entry.TextureArray.SetSamplers(0, samplers);
 | 
			
		||||
                entry.TextureArray.SetTextures(0, textures);
 | 
			
		||||
 | 
			
		||||
                _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
 | 
			
		||||
                SetTextureArray(stage, bindingInfo, entry.TextureArray);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -767,7 +767,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
            int textureBufferIndex,
 | 
			
		||||
            bool isImage,
 | 
			
		||||
            SamplerIndex samplerIndex,
 | 
			
		||||
            TextureBindingInfo bindingInfo)
 | 
			
		||||
            in TextureBindingInfo bindingInfo)
 | 
			
		||||
        {
 | 
			
		||||
            (textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex);
 | 
			
		||||
 | 
			
		||||
@@ -800,11 +800,11 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
 | 
			
		||||
                    if (isImage)
 | 
			
		||||
                    {
 | 
			
		||||
                        _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
 | 
			
		||||
                        SetImageArray(stage, bindingInfo, entry.ImageArray);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
 | 
			
		||||
                        SetTextureArray(stage, bindingInfo, entry.TextureArray);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return;
 | 
			
		||||
@@ -829,11 +829,11 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
 | 
			
		||||
                    if (isImage)
 | 
			
		||||
                    {
 | 
			
		||||
                        _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
 | 
			
		||||
                        SetImageArray(stage, bindingInfo, entry.ImageArray);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
 | 
			
		||||
                        SetTextureArray(stage, bindingInfo, entry.TextureArray);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return;
 | 
			
		||||
@@ -950,14 +950,50 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                entry.ImageArray.SetFormats(0, formats);
 | 
			
		||||
                entry.ImageArray.SetImages(0, textures);
 | 
			
		||||
 | 
			
		||||
                _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
 | 
			
		||||
                SetImageArray(stage, bindingInfo, entry.ImageArray);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                entry.TextureArray.SetSamplers(0, samplers);
 | 
			
		||||
                entry.TextureArray.SetTextures(0, textures);
 | 
			
		||||
 | 
			
		||||
                _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
 | 
			
		||||
                SetTextureArray(stage, bindingInfo, entry.TextureArray);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Updates a texture array binding on the host.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="stage">Shader stage where the array is used</param>
 | 
			
		||||
        /// <param name="bindingInfo">Array binding information</param>
 | 
			
		||||
        /// <param name="array">Texture array</param>
 | 
			
		||||
        private void SetTextureArray(ShaderStage stage, in TextureBindingInfo bindingInfo, ITextureArray array)
 | 
			
		||||
        {
 | 
			
		||||
            if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex && _context.Capabilities.MaximumExtraSets != 0)
 | 
			
		||||
            {
 | 
			
		||||
                _context.Renderer.Pipeline.SetTextureArraySeparate(stage, bindingInfo.Set, array);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, array);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Updates a image array binding on the host.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="stage">Shader stage where the array is used</param>
 | 
			
		||||
        /// <param name="bindingInfo">Array binding information</param>
 | 
			
		||||
        /// <param name="array">Image array</param>
 | 
			
		||||
        private void SetImageArray(ShaderStage stage, in TextureBindingInfo bindingInfo, IImageArray array)
 | 
			
		||||
        {
 | 
			
		||||
            if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex && _context.Capabilities.MaximumExtraSets != 0)
 | 
			
		||||
            {
 | 
			
		||||
                _context.Renderer.Pipeline.SetImageArraySeparate(stage, bindingInfo.Set, array);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, array);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -973,7 +1009,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        private CacheEntry GetOrAddEntry(
 | 
			
		||||
            TexturePool texturePool,
 | 
			
		||||
            SamplerPool samplerPool,
 | 
			
		||||
            TextureBindingInfo bindingInfo,
 | 
			
		||||
            in TextureBindingInfo bindingInfo,
 | 
			
		||||
            bool isImage,
 | 
			
		||||
            out bool isNew)
 | 
			
		||||
        {
 | 
			
		||||
@@ -1015,7 +1051,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        private CacheEntryFromBuffer GetOrAddEntry(
 | 
			
		||||
            TexturePool texturePool,
 | 
			
		||||
            SamplerPool samplerPool,
 | 
			
		||||
            TextureBindingInfo bindingInfo,
 | 
			
		||||
            in TextureBindingInfo bindingInfo,
 | 
			
		||||
            bool isImage,
 | 
			
		||||
            ref BufferBounds textureBufferBounds,
 | 
			
		||||
            out bool isNew)
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
 | 
			
		||||
                    var result = new TextureBindingInfo(
 | 
			
		||||
                        target,
 | 
			
		||||
                        descriptor.Set,
 | 
			
		||||
                        descriptor.Binding,
 | 
			
		||||
                        descriptor.ArrayLength,
 | 
			
		||||
                        descriptor.CbufSlot,
 | 
			
		||||
@@ -90,6 +91,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
                    var result = new TextureBindingInfo(
 | 
			
		||||
                        target,
 | 
			
		||||
                        format,
 | 
			
		||||
                        descriptor.Set,
 | 
			
		||||
                        descriptor.Binding,
 | 
			
		||||
                        descriptor.ArrayLength,
 | 
			
		||||
                        descriptor.CbufSlot,
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
 | 
			
		||||
        private const ushort FileFormatVersionMajor = 1;
 | 
			
		||||
        private const ushort FileFormatVersionMinor = 2;
 | 
			
		||||
        private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
 | 
			
		||||
        private const uint CodeGenVersion = 5936;
 | 
			
		||||
        private const uint CodeGenVersion = 6870;
 | 
			
		||||
 | 
			
		||||
        private const string SharedTocFileName = "shared.toc";
 | 
			
		||||
        private const string SharedDataFileName = "shared.data";
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
            _reservedImages = rrc.ReservedImages;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int CreateConstantBufferBinding(int index)
 | 
			
		||||
        public SetBindingPair CreateConstantBufferBinding(int index)
 | 
			
		||||
        {
 | 
			
		||||
            int binding;
 | 
			
		||||
 | 
			
		||||
@@ -64,10 +64,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
                binding = _resourceCounts.UniformBuffersCount++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return binding + _reservedConstantBuffers;
 | 
			
		||||
            return new SetBindingPair(_context.Capabilities.UniformBufferSetIndex, binding + _reservedConstantBuffers);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int CreateImageBinding(int count, bool isBuffer)
 | 
			
		||||
        public SetBindingPair CreateImageBinding(int count, bool isBuffer)
 | 
			
		||||
        {
 | 
			
		||||
            int binding;
 | 
			
		||||
 | 
			
		||||
@@ -96,10 +96,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
                _resourceCounts.ImagesCount += count;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return binding + _reservedImages;
 | 
			
		||||
            return new SetBindingPair(_context.Capabilities.ImageSetIndex, binding + _reservedImages);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int CreateStorageBufferBinding(int index)
 | 
			
		||||
        public SetBindingPair CreateStorageBufferBinding(int index)
 | 
			
		||||
        {
 | 
			
		||||
            int binding;
 | 
			
		||||
 | 
			
		||||
@@ -112,10 +112,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
                binding = _resourceCounts.StorageBuffersCount++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return binding + _reservedStorageBuffers;
 | 
			
		||||
            return new SetBindingPair(_context.Capabilities.StorageBufferSetIndex, binding + _reservedStorageBuffers);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int CreateTextureBinding(int count, bool isBuffer)
 | 
			
		||||
        public SetBindingPair CreateTextureBinding(int count, bool isBuffer)
 | 
			
		||||
        {
 | 
			
		||||
            int binding;
 | 
			
		||||
 | 
			
		||||
@@ -144,7 +144,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
                _resourceCounts.TexturesCount += count;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return binding + _reservedTextures;
 | 
			
		||||
            return new SetBindingPair(_context.Capabilities.TextureSetIndex, binding + _reservedTextures);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private int GetBindingFromIndex(int index, uint maxPerStage, string resourceName)
 | 
			
		||||
@@ -183,6 +183,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
            return maxPerStage * Constants.ShaderStages;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int CreateExtraSet()
 | 
			
		||||
        {
 | 
			
		||||
            if (_resourceCounts.SetsCount >= _context.Capabilities.MaximumExtraSets)
 | 
			
		||||
            {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return _context.Capabilities.ExtraSetBaseIndex + _resourceCounts.SetsCount++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int QueryHostGatherBiasPrecision() => _context.Capabilities.GatherBiasPrecision;
 | 
			
		||||
 | 
			
		||||
        public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision;
 | 
			
		||||
 
 | 
			
		||||
@@ -24,5 +24,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
        /// Total of images used by the shaders.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int ImagesCount;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Total of extra sets used by the shaders.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int SetsCount;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
using Ryujinx.Graphics.GAL;
 | 
			
		||||
using Ryujinx.Graphics.Shader;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
@@ -9,13 +10,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    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 |
 | 
			
		||||
@@ -36,8 +30,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
        private readonly int _reservedTextures;
 | 
			
		||||
        private readonly int _reservedImages;
 | 
			
		||||
 | 
			
		||||
        private readonly List<ResourceDescriptor>[] _resourceDescriptors;
 | 
			
		||||
        private readonly List<ResourceUsage>[] _resourceUsages;
 | 
			
		||||
        private List<ResourceDescriptor>[] _resourceDescriptors;
 | 
			
		||||
        private List<ResourceUsage>[] _resourceUsages;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Creates a new shader info builder.
 | 
			
		||||
@@ -51,17 +45,27 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
 | 
			
		||||
            _fragmentOutputMap = -1;
 | 
			
		||||
 | 
			
		||||
            _resourceDescriptors = new List<ResourceDescriptor>[TotalSets];
 | 
			
		||||
            _resourceUsages = new List<ResourceUsage>[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<ResourceDescriptor>[totalSets];
 | 
			
		||||
            _resourceUsages = new List<ResourceUsage>[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);
 | 
			
		||||
 | 
			
		||||
@@ -73,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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Populates descriptors and usages for vertex as compute and transform feedback emulation reserved resources.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="stages">Shader stages where the resources are used</param>
 | 
			
		||||
        /// <param name="type">Resource type</param>
 | 
			
		||||
        /// <param name="setIndex">Resource set index where the resources are used</param>
 | 
			
		||||
        /// <param name="start">First binding number</param>
 | 
			
		||||
        /// <param name="count">Amount of bindings</param>
 | 
			
		||||
        private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count)
 | 
			
		||||
        {
 | 
			
		||||
            AddDescriptor(stages, type, setIndex, start, count);
 | 
			
		||||
@@ -127,18 +139,23 @@ 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;
 | 
			
		||||
 | 
			
		||||
            AddArrayDescriptors(info.Textures, stages, TextureSetIndex, isImage: false);
 | 
			
		||||
            AddArrayDescriptors(info.Images, stages, TextureSetIndex, isImage: true);
 | 
			
		||||
            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);
 | 
			
		||||
 | 
			
		||||
            AddUsage(info.CBuffers, stages, UniformSetIndex, isStorage: false);
 | 
			
		||||
            AddUsage(info.SBuffers, stages, StorageSetIndex, isStorage: true);
 | 
			
		||||
            AddUsage(info.Textures, stages, TextureSetIndex, isImage: false);
 | 
			
		||||
            AddUsage(info.Images, stages, ImageSetIndex, isImage: true);
 | 
			
		||||
            AddArrayDescriptors(info.Textures, stages, isImage: false);
 | 
			
		||||
            AddArrayDescriptors(info.Images, stages, isImage: true);
 | 
			
		||||
 | 
			
		||||
            AddUsage(info.CBuffers, stages, isStorage: false);
 | 
			
		||||
            AddUsage(info.SBuffers, stages, isStorage: true);
 | 
			
		||||
            AddUsage(info.Textures, stages, isImage: false);
 | 
			
		||||
            AddUsage(info.Images, stages, isImage: true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@@ -177,9 +194,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="textures">Textures to be added</param>
 | 
			
		||||
        /// <param name="stages">Stages where the textures are used</param>
 | 
			
		||||
        /// <param name="setIndex">Descriptor set index where the textures will be bound</param>
 | 
			
		||||
        /// <param name="isImage">True for images, false for textures</param>
 | 
			
		||||
        private void AddArrayDescriptors(IEnumerable<TextureDescriptor> textures, ResourceStages stages, int setIndex, bool isImage)
 | 
			
		||||
        private void AddArrayDescriptors(IEnumerable<TextureDescriptor> textures, ResourceStages stages, bool isImage)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (TextureDescriptor texture in textures)
 | 
			
		||||
            {
 | 
			
		||||
@@ -187,7 +203,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
                {
 | 
			
		||||
                    ResourceType type = GetTextureResourceType(texture, isImage);
 | 
			
		||||
 | 
			
		||||
                    _resourceDescriptors[setIndex].Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages));
 | 
			
		||||
                    GetDescriptors(texture.Set).Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -213,13 +229,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="buffers">Buffers to be added</param>
 | 
			
		||||
        /// <param name="stages">Stages where the buffers are used</param>
 | 
			
		||||
        /// <param name="setIndex">Descriptor set index where the buffers will be bound</param>
 | 
			
		||||
        /// <param name="isStorage">True for storage buffers, false for uniform buffers</param>
 | 
			
		||||
        private void AddUsage(IEnumerable<BufferDescriptor> buffers, ResourceStages stages, int setIndex, bool isStorage)
 | 
			
		||||
        private void AddUsage(IEnumerable<BufferDescriptor> buffers, ResourceStages stages, bool isStorage)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (BufferDescriptor buffer in buffers)
 | 
			
		||||
            {
 | 
			
		||||
                _resourceUsages[setIndex].Add(new ResourceUsage(
 | 
			
		||||
                GetUsages(buffer.Set).Add(new ResourceUsage(
 | 
			
		||||
                    buffer.Binding,
 | 
			
		||||
                    1,
 | 
			
		||||
                    isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer,
 | 
			
		||||
@@ -232,18 +247,65 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="textures">Textures to be added</param>
 | 
			
		||||
        /// <param name="stages">Stages where the textures are used</param>
 | 
			
		||||
        /// <param name="setIndex">Descriptor set index where the textures will be bound</param>
 | 
			
		||||
        /// <param name="isImage">True for images, false for textures</param>
 | 
			
		||||
        private void AddUsage(IEnumerable<TextureDescriptor> textures, ResourceStages stages, int setIndex, bool isImage)
 | 
			
		||||
        private void AddUsage(IEnumerable<TextureDescriptor> textures, ResourceStages stages, bool isImage)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (TextureDescriptor texture in textures)
 | 
			
		||||
            {
 | 
			
		||||
                ResourceType type = GetTextureResourceType(texture, isImage);
 | 
			
		||||
 | 
			
		||||
                _resourceUsages[setIndex].Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages));
 | 
			
		||||
                GetUsages(texture.Set).Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the list of resource descriptors for a given set index. A new list will be created if needed.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="setIndex">Resource set index</param>
 | 
			
		||||
        /// <returns>List of resource descriptors</returns>
 | 
			
		||||
        private List<ResourceDescriptor> GetDescriptors(int setIndex)
 | 
			
		||||
        {
 | 
			
		||||
            if (_resourceDescriptors.Length <= setIndex)
 | 
			
		||||
            {
 | 
			
		||||
                int oldLength = _resourceDescriptors.Length;
 | 
			
		||||
                Array.Resize(ref _resourceDescriptors, setIndex + 1);
 | 
			
		||||
 | 
			
		||||
                for (int index = oldLength; index <= setIndex; index++)
 | 
			
		||||
                {
 | 
			
		||||
                    _resourceDescriptors[index] = new();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return _resourceDescriptors[setIndex];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the list of resource usages for a given set index. A new list will be created if needed.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="setIndex">Resource set index</param>
 | 
			
		||||
        /// <returns>List of resource usages</returns>
 | 
			
		||||
        private List<ResourceUsage> GetUsages(int setIndex)
 | 
			
		||||
        {
 | 
			
		||||
            if (_resourceUsages.Length <= setIndex)
 | 
			
		||||
            {
 | 
			
		||||
                int oldLength = _resourceUsages.Length;
 | 
			
		||||
                Array.Resize(ref _resourceUsages, setIndex + 1);
 | 
			
		||||
 | 
			
		||||
                for (int index = oldLength; index <= setIndex; index++)
 | 
			
		||||
                {
 | 
			
		||||
                    _resourceUsages[index] = new();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return _resourceUsages[setIndex];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets a resource type from a texture descriptor.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="texture">Texture descriptor</param>
 | 
			
		||||
        /// <param name="isImage">Whether the texture is a image texture (writable) or not (sampled)</param>
 | 
			
		||||
        /// <returns>Resource type</returns>
 | 
			
		||||
        private static ResourceType GetTextureResourceType(TextureDescriptor texture, bool isImage)
 | 
			
		||||
        {
 | 
			
		||||
            bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
 | 
			
		||||
@@ -278,10 +340,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
        /// <returns>Shader information</returns>
 | 
			
		||||
        public ShaderInfo Build(ProgramPipelineState? pipeline, bool fromCache = false)
 | 
			
		||||
        {
 | 
			
		||||
            var descriptors = new ResourceDescriptorCollection[TotalSets];
 | 
			
		||||
            var usages = new ResourceUsageCollection[TotalSets];
 | 
			
		||||
            int totalSets = _resourceDescriptors.Length;
 | 
			
		||||
 | 
			
		||||
            for (int index = 0; index < TotalSets; index++)
 | 
			
		||||
            var descriptors = new ResourceDescriptorCollection[totalSets];
 | 
			
		||||
            var usages = new ResourceUsageCollection[totalSets];
 | 
			
		||||
 | 
			
		||||
            for (int index = 0; index < totalSets; index++)
 | 
			
		||||
            {
 | 
			
		||||
                descriptors[index] = new ResourceDescriptorCollection(_resourceDescriptors[index].ToArray().AsReadOnly());
 | 
			
		||||
                usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly());
 | 
			
		||||
 
 | 
			
		||||
@@ -187,6 +187,12 @@ namespace Ryujinx.Graphics.OpenGL
 | 
			
		||||
                supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
 | 
			
		||||
                supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
 | 
			
		||||
                supportsDepthClipControl: true,
 | 
			
		||||
                uniformBufferSetIndex: 0,
 | 
			
		||||
                storageBufferSetIndex: 1,
 | 
			
		||||
                textureSetIndex: 2,
 | 
			
		||||
                imageSetIndex: 3,
 | 
			
		||||
                extraSetBaseIndex: 0,
 | 
			
		||||
                maximumExtraSets: 0,
 | 
			
		||||
                maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
 | 
			
		||||
                maximumStorageBuffersPerStage: 16,
 | 
			
		||||
                maximumTexturesPerStage: 32,
 | 
			
		||||
 
 | 
			
		||||
@@ -963,6 +963,11 @@ namespace Ryujinx.Graphics.OpenGL
 | 
			
		||||
            (array as ImageArray).Bind(binding);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
 | 
			
		||||
        {
 | 
			
		||||
            throw new NotSupportedException("OpenGL does not support descriptor sets.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetIndexBuffer(BufferRange buffer, IndexType type)
 | 
			
		||||
        {
 | 
			
		||||
            _elementsType = type.Convert();
 | 
			
		||||
@@ -1312,6 +1317,11 @@ namespace Ryujinx.Graphics.OpenGL
 | 
			
		||||
            (array as TextureArray).Bind(binding);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
 | 
			
		||||
        {
 | 
			
		||||
            throw new NotSupportedException("OpenGL does not support descriptor sets.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
 | 
			
		||||
        {
 | 
			
		||||
            if (_tfEnabled)
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,16 @@ namespace Ryujinx.Graphics.Shader
 | 
			
		||||
    {
 | 
			
		||||
        // New fields should be added to the end of the struct to keep disk shader cache compatibility.
 | 
			
		||||
 | 
			
		||||
        public readonly int Set;
 | 
			
		||||
        public readonly int Binding;
 | 
			
		||||
        public readonly byte Slot;
 | 
			
		||||
        public readonly byte SbCbSlot;
 | 
			
		||||
        public readonly ushort SbCbOffset;
 | 
			
		||||
        public readonly BufferUsageFlags Flags;
 | 
			
		||||
 | 
			
		||||
        public BufferDescriptor(int binding, int slot)
 | 
			
		||||
        public BufferDescriptor(int set, int binding, int slot)
 | 
			
		||||
        {
 | 
			
		||||
            Set = set;
 | 
			
		||||
            Binding = binding;
 | 
			
		||||
            Slot = (byte)slot;
 | 
			
		||||
            SbCbSlot = 0;
 | 
			
		||||
@@ -19,8 +21,9 @@ namespace Ryujinx.Graphics.Shader
 | 
			
		||||
            Flags = BufferUsageFlags.None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public BufferDescriptor(int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags)
 | 
			
		||||
        public BufferDescriptor(int set, int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags)
 | 
			
		||||
        {
 | 
			
		||||
            Set = set;
 | 
			
		||||
            Binding = binding;
 | 
			
		||||
            Slot = (byte)slot;
 | 
			
		||||
            SbCbSlot = (byte)sbCbSlot;
 | 
			
		||||
 
 | 
			
		||||
@@ -462,7 +462,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                context.Properties.Textures.TryGetValue(texOp.Binding, out TextureDefinition definition);
 | 
			
		||||
                context.Properties.Textures.TryGetValue(texOp.GetTextureSetAndBinding(), out TextureDefinition definition);
 | 
			
		||||
                bool hasLod = !definition.Type.HasFlag(SamplerType.Multisample) && (definition.Type & SamplerType.Mask) != SamplerType.TextureBuffer;
 | 
			
		||||
                string texCall;
 | 
			
		||||
 | 
			
		||||
@@ -639,7 +639,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
 | 
			
		||||
 | 
			
		||||
        private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
 | 
			
		||||
        {
 | 
			
		||||
            TextureDefinition textureDefinition = context.Properties.Textures[texOp.Binding];
 | 
			
		||||
            TextureDefinition textureDefinition = context.Properties.Textures[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
            string name = textureDefinition.Name;
 | 
			
		||||
 | 
			
		||||
            if (textureDefinition.ArrayLength != 1)
 | 
			
		||||
@@ -649,7 +649,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
 | 
			
		||||
 | 
			
		||||
            if (texOp.IsSeparate)
 | 
			
		||||
            {
 | 
			
		||||
                TextureDefinition samplerDefinition = context.Properties.Textures[texOp.SamplerBinding];
 | 
			
		||||
                TextureDefinition samplerDefinition = context.Properties.Textures[texOp.GetSamplerSetAndBinding()];
 | 
			
		||||
                string samplerName = samplerDefinition.Name;
 | 
			
		||||
 | 
			
		||||
                if (samplerDefinition.ArrayLength != 1)
 | 
			
		||||
@@ -665,7 +665,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
 | 
			
		||||
 | 
			
		||||
        private static string GetImageName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
 | 
			
		||||
        {
 | 
			
		||||
            TextureDefinition definition = context.Properties.Images[texOp.Binding];
 | 
			
		||||
            TextureDefinition definition = context.Properties.Images[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
            string name = definition.Name;
 | 
			
		||||
 | 
			
		||||
            if (definition.ArrayLength != 1)
 | 
			
		||||
 
 | 
			
		||||
@@ -33,9 +33,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
        public Dictionary<int, Instruction> LocalMemories { get; } = new();
 | 
			
		||||
        public Dictionary<int, Instruction> SharedMemories { get; } = new();
 | 
			
		||||
 | 
			
		||||
        public Dictionary<int, SamplerType> SamplersTypes { get; } = new();
 | 
			
		||||
        public Dictionary<int, SamplerDeclaration> Samplers { get; } = new();
 | 
			
		||||
        public Dictionary<int, ImageDeclaration> Images { get; } = new();
 | 
			
		||||
        public Dictionary<SetBindingPair, SamplerType> SamplersTypes { get; } = new();
 | 
			
		||||
        public Dictionary<SetBindingPair, SamplerDeclaration> Samplers { get; } = new();
 | 
			
		||||
        public Dictionary<SetBindingPair, ImageDeclaration> Images { get; } = new();
 | 
			
		||||
 | 
			
		||||
        public Dictionary<IoDefinition, Instruction> Inputs { get; } = new();
 | 
			
		||||
        public Dictionary<IoDefinition, Instruction> Outputs { get; } = new();
 | 
			
		||||
 
 | 
			
		||||
@@ -208,13 +208,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
 | 
			
		||||
                var sampledImageVariable = context.Variable(sampledImageArrayPointerType, StorageClass.UniformConstant);
 | 
			
		||||
 | 
			
		||||
                context.Samplers.Add(sampler.Binding, new SamplerDeclaration(
 | 
			
		||||
                context.Samplers.Add(new(sampler.Set, sampler.Binding), new SamplerDeclaration(
 | 
			
		||||
                    imageType,
 | 
			
		||||
                    sampledImageType,
 | 
			
		||||
                    sampledImagePointerType,
 | 
			
		||||
                    sampledImageVariable,
 | 
			
		||||
                    sampler.ArrayLength != 1));
 | 
			
		||||
                context.SamplersTypes.Add(sampler.Binding, sampler.Type);
 | 
			
		||||
                context.SamplersTypes.Add(new(sampler.Set, sampler.Binding), sampler.Type);
 | 
			
		||||
 | 
			
		||||
                context.Name(sampledImageVariable, sampler.Name);
 | 
			
		||||
                context.Decorate(sampledImageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
 | 
			
		||||
@@ -256,7 +256,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
 | 
			
		||||
                var imageVariable = context.Variable(imageArrayPointerType, StorageClass.UniformConstant);
 | 
			
		||||
 | 
			
		||||
                context.Images.Add(image.Binding, new ImageDeclaration(imageType, imagePointerType, imageVariable, image.ArrayLength != 1));
 | 
			
		||||
                context.Images.Add(new(image.Set, image.Binding), new ImageDeclaration(imageType, imagePointerType, imageVariable, image.ArrayLength != 1));
 | 
			
		||||
 | 
			
		||||
                context.Name(imageVariable, image.Name);
 | 
			
		||||
                context.Decorate(imageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
 | 
			
		||||
 
 | 
			
		||||
@@ -602,7 +602,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
                return context.Get(type, texOp.GetSource(srcIndex++));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ImageDeclaration declaration = context.Images[texOp.Binding];
 | 
			
		||||
            ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
            SpvInstruction image = declaration.Image;
 | 
			
		||||
 | 
			
		||||
            SpvInstruction resultType = context.GetType(componentType);
 | 
			
		||||
@@ -681,7 +681,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
                return context.Get(type, texOp.GetSource(srcIndex++));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ImageDeclaration declaration = context.Images[texOp.Binding];
 | 
			
		||||
            ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
            SpvInstruction image = declaration.Image;
 | 
			
		||||
 | 
			
		||||
            if (declaration.IsIndexed)
 | 
			
		||||
@@ -738,7 +738,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
                return context.Get(type, texOp.GetSource(srcIndex++));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ImageDeclaration declaration = context.Images[texOp.Binding];
 | 
			
		||||
            ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
            SpvInstruction image = declaration.Image;
 | 
			
		||||
 | 
			
		||||
            if (declaration.IsIndexed)
 | 
			
		||||
@@ -837,7 +837,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
                return context.Get(type, texOp.GetSource(srcIndex++));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SamplerDeclaration declaration = context.Samplers[texOp.Binding];
 | 
			
		||||
            SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
            SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
 | 
			
		||||
 | 
			
		||||
            int pCount = texOp.Type.GetDimensions();
 | 
			
		||||
@@ -1161,7 +1161,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
                return context.Get(type, texOp.GetSource(srcIndex++));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SamplerDeclaration declaration = context.Samplers[texOp.Binding];
 | 
			
		||||
            SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
            SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
 | 
			
		||||
 | 
			
		||||
            int coordsCount = texOp.Type.GetDimensions();
 | 
			
		||||
@@ -1433,7 +1433,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
 | 
			
		||||
            int srcIndex = 0;
 | 
			
		||||
 | 
			
		||||
            SamplerDeclaration declaration = context.Samplers[texOp.Binding];
 | 
			
		||||
            SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
            SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
 | 
			
		||||
 | 
			
		||||
            image = context.Image(declaration.ImageType, image);
 | 
			
		||||
@@ -1449,7 +1449,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
 | 
			
		||||
            int srcIndex = 0;
 | 
			
		||||
 | 
			
		||||
            SamplerDeclaration declaration = context.Samplers[texOp.Binding];
 | 
			
		||||
            SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
            SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
 | 
			
		||||
 | 
			
		||||
            image = context.Image(declaration.ImageType, image);
 | 
			
		||||
@@ -1460,7 +1460,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var type = context.SamplersTypes[texOp.Binding];
 | 
			
		||||
                var type = context.SamplersTypes[texOp.GetTextureSetAndBinding()];
 | 
			
		||||
                bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer;
 | 
			
		||||
 | 
			
		||||
                int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions();
 | 
			
		||||
@@ -1889,7 +1889,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 | 
			
		||||
            {
 | 
			
		||||
                image = context.Load(declaration.ImageType, image);
 | 
			
		||||
 | 
			
		||||
                SamplerDeclaration samplerDeclaration = context.Samplers[texOp.SamplerBinding];
 | 
			
		||||
                SamplerDeclaration samplerDeclaration = context.Samplers[texOp.GetSamplerSetAndBinding()];
 | 
			
		||||
 | 
			
		||||
                SpvInstruction sampler = samplerDeclaration.Image;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,34 +27,43 @@ namespace Ryujinx.Graphics.Shader
 | 
			
		||||
        ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Queries the binding number of a constant buffer.
 | 
			
		||||
        /// Gets the binding number of a constant buffer.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="index">Constant buffer index</param>
 | 
			
		||||
        /// <returns>Binding number</returns>
 | 
			
		||||
        int CreateConstantBufferBinding(int index);
 | 
			
		||||
        SetBindingPair CreateConstantBufferBinding(int index);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Queries the binding number of an image.
 | 
			
		||||
        /// Gets the binding number of an image.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="count">For array of images, the number of elements of the array, otherwise it should be 1</param>
 | 
			
		||||
        /// <param name="isBuffer">Indicates if the image is a buffer image</param>
 | 
			
		||||
        /// <returns>Binding number</returns>
 | 
			
		||||
        int CreateImageBinding(int count, bool isBuffer);
 | 
			
		||||
        SetBindingPair CreateImageBinding(int count, bool isBuffer);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Queries the binding number of a storage buffer.
 | 
			
		||||
        /// Gets the binding number of a storage buffer.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="index">Storage buffer index</param>
 | 
			
		||||
        /// <returns>Binding number</returns>
 | 
			
		||||
        int CreateStorageBufferBinding(int index);
 | 
			
		||||
        SetBindingPair CreateStorageBufferBinding(int index);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Queries the binding number of a texture.
 | 
			
		||||
        /// Gets the binding number of a texture.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="count">For array of textures, the number of elements of the array, otherwise it should be 1</param>
 | 
			
		||||
        /// <param name="isBuffer">Indicates if the texture is a buffer texture</param>
 | 
			
		||||
        /// <returns>Binding number</returns>
 | 
			
		||||
        int CreateTextureBinding(int count, bool isBuffer);
 | 
			
		||||
        SetBindingPair CreateTextureBinding(int count, bool isBuffer);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the set index for an additional set, or -1 if there's no extra set available.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns>Extra set index, or -1 if not available</returns>
 | 
			
		||||
        int CreateExtraSet()
 | 
			
		||||
        {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Queries Local Size X for compute shaders.
 | 
			
		||||
 
 | 
			
		||||
@@ -278,7 +278,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                flags |= TextureFlags.Bindless;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
            SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                Instruction.ImageAtomic,
 | 
			
		||||
                type,
 | 
			
		||||
                format,
 | 
			
		||||
@@ -286,7 +286,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                TextureOperation.DefaultCbufSlot,
 | 
			
		||||
                imm);
 | 
			
		||||
 | 
			
		||||
            Operand res = context.ImageAtomic(type, format, flags, binding, sources);
 | 
			
		||||
            Operand res = context.ImageAtomic(type, format, flags, setAndBinding, sources);
 | 
			
		||||
 | 
			
		||||
            context.Copy(d, res);
 | 
			
		||||
        }
 | 
			
		||||
@@ -389,7 +389,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
 | 
			
		||||
                TextureFormat format = isBindless ? TextureFormat.Unknown : ShaderProperties.GetTextureFormat(context.TranslatorContext.GpuAccessor, handle);
 | 
			
		||||
 | 
			
		||||
                int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                    Instruction.ImageLoad,
 | 
			
		||||
                    type,
 | 
			
		||||
                    format,
 | 
			
		||||
@@ -397,7 +397,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                    TextureOperation.DefaultCbufSlot,
 | 
			
		||||
                    handle);
 | 
			
		||||
 | 
			
		||||
                context.ImageLoad(type, format, flags, binding, (int)componentMask, dests, sources);
 | 
			
		||||
                context.ImageLoad(type, format, flags, setAndBinding, (int)componentMask, dests, sources);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
@@ -432,7 +432,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
 | 
			
		||||
                TextureFormat format = GetTextureFormat(size);
 | 
			
		||||
 | 
			
		||||
                int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                    Instruction.ImageLoad,
 | 
			
		||||
                    type,
 | 
			
		||||
                    format,
 | 
			
		||||
@@ -440,7 +440,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                    TextureOperation.DefaultCbufSlot,
 | 
			
		||||
                    handle);
 | 
			
		||||
 | 
			
		||||
                context.ImageLoad(type, format, flags, binding, compMask, dests, sources);
 | 
			
		||||
                context.ImageLoad(type, format, flags, setAndBinding, compMask, dests, sources);
 | 
			
		||||
 | 
			
		||||
                switch (size)
 | 
			
		||||
                {
 | 
			
		||||
@@ -552,7 +552,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                flags |= TextureFlags.Bindless;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
            SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                Instruction.ImageAtomic,
 | 
			
		||||
                type,
 | 
			
		||||
                format,
 | 
			
		||||
@@ -560,7 +560,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                TextureOperation.DefaultCbufSlot,
 | 
			
		||||
                imm);
 | 
			
		||||
 | 
			
		||||
            context.ImageAtomic(type, format, flags, binding, sources);
 | 
			
		||||
            context.ImageAtomic(type, format, flags, setAndBinding, sources);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void EmitSust(
 | 
			
		||||
@@ -679,7 +679,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                flags |= TextureFlags.Coherent;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
            SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                Instruction.ImageStore,
 | 
			
		||||
                type,
 | 
			
		||||
                format,
 | 
			
		||||
@@ -687,7 +687,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                TextureOperation.DefaultCbufSlot,
 | 
			
		||||
                handle);
 | 
			
		||||
 | 
			
		||||
            context.ImageStore(type, format, flags, binding, sources);
 | 
			
		||||
            context.ImageStore(type, format, flags, setAndBinding, sources);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static int GetComponentSizeInBytesLog2(SuatomSize size)
 | 
			
		||||
 
 | 
			
		||||
@@ -885,7 +885,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                return Register(dest++, RegisterType.Gpr);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
            SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                Instruction.Lod,
 | 
			
		||||
                type,
 | 
			
		||||
                TextureFormat.Unknown,
 | 
			
		||||
@@ -913,7 +913,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        // The instruction component order is the inverse of GLSL's.
 | 
			
		||||
                        Operand res = context.Lod(type, flags, binding, compIndex ^ 1, sources);
 | 
			
		||||
                        Operand res = context.Lod(type, flags, setAndBinding, compIndex ^ 1, sources);
 | 
			
		||||
 | 
			
		||||
                        res = context.FPMultiply(res, ConstF(256.0f));
 | 
			
		||||
 | 
			
		||||
@@ -1116,12 +1116,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
 | 
			
		||||
            int binding;
 | 
			
		||||
            SetBindingPair setAndBinding;
 | 
			
		||||
 | 
			
		||||
            switch (query)
 | 
			
		||||
            {
 | 
			
		||||
                case TexQuery.TexHeaderDimension:
 | 
			
		||||
                    binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                    setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                        Instruction.TextureQuerySize,
 | 
			
		||||
                        type,
 | 
			
		||||
                        TextureFormat.Unknown,
 | 
			
		||||
@@ -1140,13 +1140,13 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            context.Copy(d, context.TextureQuerySize(type, flags, binding, compIndex, sources));
 | 
			
		||||
                            context.Copy(d, context.TextureQuerySize(type, flags, setAndBinding, compIndex, sources));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case TexQuery.TexHeaderTextureType:
 | 
			
		||||
                    binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                    setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                        Instruction.TextureQuerySamples,
 | 
			
		||||
                        type,
 | 
			
		||||
                        TextureFormat.Unknown,
 | 
			
		||||
@@ -1171,7 +1171,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
 | 
			
		||||
                        if (d != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            context.Copy(d, context.TextureQuerySamples(type, flags, binding, sources));
 | 
			
		||||
                            context.Copy(d, context.TextureQuerySamples(type, flags, setAndBinding, sources));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -1191,7 +1191,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
            Operand[] dests,
 | 
			
		||||
            Operand[] sources)
 | 
			
		||||
        {
 | 
			
		||||
            int binding = flags.HasFlag(TextureFlags.Bindless) ? 0 : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
            SetBindingPair setAndBinding = flags.HasFlag(TextureFlags.Bindless) ? default : context.ResourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                Instruction.TextureSample,
 | 
			
		||||
                type,
 | 
			
		||||
                TextureFormat.Unknown,
 | 
			
		||||
@@ -1199,7 +1199,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 | 
			
		||||
                TextureOperation.DefaultCbufSlot,
 | 
			
		||||
                handle);
 | 
			
		||||
 | 
			
		||||
            context.TextureSample(type, flags, binding, componentMask, dests, sources);
 | 
			
		||||
            context.TextureSample(type, flags, setAndBinding, componentMask, dests, sources);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static SamplerType ConvertSamplerType(TexDim dimensions)
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,9 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
 | 
			
		||||
        public TextureFormat Format { get; set; }
 | 
			
		||||
        public TextureFlags Flags { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public int Set { get; private set; }
 | 
			
		||||
        public int Binding { get; private set; }
 | 
			
		||||
        public int SamplerSet { get; private set; }
 | 
			
		||||
        public int SamplerBinding { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public TextureOperation(
 | 
			
		||||
@@ -16,6 +18,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFormat format,
 | 
			
		||||
            TextureFlags flags,
 | 
			
		||||
            int set,
 | 
			
		||||
            int binding,
 | 
			
		||||
            int compIndex,
 | 
			
		||||
            Operand[] dests,
 | 
			
		||||
@@ -24,24 +27,28 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
 | 
			
		||||
            Type = type;
 | 
			
		||||
            Format = format;
 | 
			
		||||
            Flags = flags;
 | 
			
		||||
            Set = set;
 | 
			
		||||
            Binding = binding;
 | 
			
		||||
            SamplerSet = -1;
 | 
			
		||||
            SamplerBinding = -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void TurnIntoArray(int binding)
 | 
			
		||||
        public void TurnIntoArray(SetBindingPair setAndBinding)
 | 
			
		||||
        {
 | 
			
		||||
            Flags &= ~TextureFlags.Bindless;
 | 
			
		||||
            Binding = binding;
 | 
			
		||||
            Set = setAndBinding.SetIndex;
 | 
			
		||||
            Binding = setAndBinding.Binding;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void TurnIntoArray(int textureBinding, int samplerBinding)
 | 
			
		||||
        public void TurnIntoArray(SetBindingPair textureSetAndBinding, SetBindingPair samplerSetAndBinding)
 | 
			
		||||
        {
 | 
			
		||||
            TurnIntoArray(textureBinding);
 | 
			
		||||
            TurnIntoArray(textureSetAndBinding);
 | 
			
		||||
 | 
			
		||||
            SamplerBinding = samplerBinding;
 | 
			
		||||
            SamplerSet = samplerSetAndBinding.SetIndex;
 | 
			
		||||
            SamplerBinding = samplerSetAndBinding.Binding;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetBinding(int binding)
 | 
			
		||||
        public void SetBinding(SetBindingPair setAndBinding)
 | 
			
		||||
        {
 | 
			
		||||
            if ((Flags & TextureFlags.Bindless) != 0)
 | 
			
		||||
            {
 | 
			
		||||
@@ -50,7 +57,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
 | 
			
		||||
                RemoveSource(0);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Binding = binding;
 | 
			
		||||
            Set = setAndBinding.SetIndex;
 | 
			
		||||
            Binding = setAndBinding.Binding;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetLodLevelFlag()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								src/Ryujinx.Graphics.Shader/SetBindingPair.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/Ryujinx.Graphics.Shader/SetBindingPair.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
namespace Ryujinx.Graphics.Shader
 | 
			
		||||
{
 | 
			
		||||
    public readonly record struct SetBindingPair(int SetIndex, int Binding);
 | 
			
		||||
}
 | 
			
		||||
@@ -8,7 +8,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 | 
			
		||||
        public TextureFormat Format { get; }
 | 
			
		||||
        public TextureFlags Flags { get; }
 | 
			
		||||
 | 
			
		||||
        public int Set { get; }
 | 
			
		||||
        public int Binding { get; }
 | 
			
		||||
        public int SamplerSet { get; }
 | 
			
		||||
        public int SamplerBinding { get; }
 | 
			
		||||
 | 
			
		||||
        public bool IsSeparate => SamplerBinding >= 0;
 | 
			
		||||
@@ -18,7 +20,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFormat format,
 | 
			
		||||
            TextureFlags flags,
 | 
			
		||||
            int set,
 | 
			
		||||
            int binding,
 | 
			
		||||
            int samplerSet,
 | 
			
		||||
            int samplerBinding,
 | 
			
		||||
            int index,
 | 
			
		||||
            params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
 | 
			
		||||
@@ -26,8 +30,20 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 | 
			
		||||
            Type = type;
 | 
			
		||||
            Format = format;
 | 
			
		||||
            Flags = flags;
 | 
			
		||||
            Set = set;
 | 
			
		||||
            Binding = binding;
 | 
			
		||||
            SamplerSet = samplerSet;
 | 
			
		||||
            SamplerBinding = samplerBinding;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public SetBindingPair GetTextureSetAndBinding()
 | 
			
		||||
        {
 | 
			
		||||
            return new SetBindingPair(Set, Binding);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public SetBindingPair GetSamplerSetAndBinding()
 | 
			
		||||
        {
 | 
			
		||||
            return new SetBindingPair(SamplerSet, SamplerBinding);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,15 +6,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Dictionary<int, BufferDefinition> _constantBuffers;
 | 
			
		||||
        private readonly Dictionary<int, BufferDefinition> _storageBuffers;
 | 
			
		||||
        private readonly Dictionary<int, TextureDefinition> _textures;
 | 
			
		||||
        private readonly Dictionary<int, TextureDefinition> _images;
 | 
			
		||||
        private readonly Dictionary<SetBindingPair, TextureDefinition> _textures;
 | 
			
		||||
        private readonly Dictionary<SetBindingPair, TextureDefinition> _images;
 | 
			
		||||
        private readonly Dictionary<int, MemoryDefinition> _localMemories;
 | 
			
		||||
        private readonly Dictionary<int, MemoryDefinition> _sharedMemories;
 | 
			
		||||
 | 
			
		||||
        public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers;
 | 
			
		||||
        public IReadOnlyDictionary<int, BufferDefinition> StorageBuffers => _storageBuffers;
 | 
			
		||||
        public IReadOnlyDictionary<int, TextureDefinition> Textures => _textures;
 | 
			
		||||
        public IReadOnlyDictionary<int, TextureDefinition> Images => _images;
 | 
			
		||||
        public IReadOnlyDictionary<SetBindingPair, TextureDefinition> Textures => _textures;
 | 
			
		||||
        public IReadOnlyDictionary<SetBindingPair, TextureDefinition> Images => _images;
 | 
			
		||||
        public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
 | 
			
		||||
        public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
 | 
			
		||||
 | 
			
		||||
@@ -22,8 +22,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 | 
			
		||||
        {
 | 
			
		||||
            _constantBuffers = new Dictionary<int, BufferDefinition>();
 | 
			
		||||
            _storageBuffers = new Dictionary<int, BufferDefinition>();
 | 
			
		||||
            _textures = new Dictionary<int, TextureDefinition>();
 | 
			
		||||
            _images = new Dictionary<int, TextureDefinition>();
 | 
			
		||||
            _textures = new Dictionary<SetBindingPair, TextureDefinition>();
 | 
			
		||||
            _images = new Dictionary<SetBindingPair, TextureDefinition>();
 | 
			
		||||
            _localMemories = new Dictionary<int, MemoryDefinition>();
 | 
			
		||||
            _sharedMemories = new Dictionary<int, MemoryDefinition>();
 | 
			
		||||
        }
 | 
			
		||||
@@ -40,12 +40,12 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 | 
			
		||||
 | 
			
		||||
        public void AddOrUpdateTexture(TextureDefinition definition)
 | 
			
		||||
        {
 | 
			
		||||
            _textures[definition.Binding] = definition;
 | 
			
		||||
            _textures[new(definition.Set, definition.Binding)] = definition;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AddOrUpdateImage(TextureDefinition definition)
 | 
			
		||||
        {
 | 
			
		||||
            _images[definition.Binding] = definition;
 | 
			
		||||
            _images[new(definition.Set, definition.Binding)] = definition;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int AddLocalMemory(MemoryDefinition definition)
 | 
			
		||||
 
 | 
			
		||||
@@ -169,7 +169,17 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 | 
			
		||||
 | 
			
		||||
            AstTextureOperation GetAstTextureOperation(TextureOperation texOp)
 | 
			
		||||
            {
 | 
			
		||||
                return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.SamplerBinding, texOp.Index, sources);
 | 
			
		||||
                return new AstTextureOperation(
 | 
			
		||||
                    inst,
 | 
			
		||||
                    texOp.Type,
 | 
			
		||||
                    texOp.Format,
 | 
			
		||||
                    texOp.Flags,
 | 
			
		||||
                    texOp.Set,
 | 
			
		||||
                    texOp.Binding,
 | 
			
		||||
                    texOp.SamplerSet,
 | 
			
		||||
                    texOp.SamplerBinding,
 | 
			
		||||
                    texOp.Index,
 | 
			
		||||
                    sources);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int componentsCount = BitOperations.PopCount((uint)operation.Index);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.Shader
 | 
			
		||||
    {
 | 
			
		||||
        // New fields should be added to the end of the struct to keep disk shader cache compatibility.
 | 
			
		||||
 | 
			
		||||
        public readonly int Set;
 | 
			
		||||
        public readonly int Binding;
 | 
			
		||||
 | 
			
		||||
        public readonly SamplerType Type;
 | 
			
		||||
@@ -18,6 +19,7 @@ namespace Ryujinx.Graphics.Shader
 | 
			
		||||
        public readonly TextureUsageFlags Flags;
 | 
			
		||||
 | 
			
		||||
        public TextureDescriptor(
 | 
			
		||||
            int set,
 | 
			
		||||
            int binding,
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFormat format,
 | 
			
		||||
@@ -27,6 +29,7 @@ namespace Ryujinx.Graphics.Shader
 | 
			
		||||
            bool separate,
 | 
			
		||||
            TextureUsageFlags flags)
 | 
			
		||||
        {
 | 
			
		||||
            Set = set;
 | 
			
		||||
            Binding = binding;
 | 
			
		||||
            Type = type;
 | 
			
		||||
            Format = format;
 | 
			
		||||
 
 | 
			
		||||
@@ -124,7 +124,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                    this.TextureSample(
 | 
			
		||||
                        SamplerType.TextureBuffer,
 | 
			
		||||
                        TextureFlags.IntCoords,
 | 
			
		||||
                        ResourceManager.Reservations.IndexBufferTextureBinding,
 | 
			
		||||
                        ResourceManager.Reservations.GetIndexBufferTextureSetAndBinding(),
 | 
			
		||||
                        1,
 | 
			
		||||
                        new[] { vertexIndexVr },
 | 
			
		||||
                        new[] { this.IAdd(ibBaseOffset, outputVertexOffset) });
 | 
			
		||||
@@ -145,7 +145,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                        this.TextureSample(
 | 
			
		||||
                            SamplerType.TextureBuffer,
 | 
			
		||||
                            TextureFlags.IntCoords,
 | 
			
		||||
                            ResourceManager.Reservations.TopologyRemapBufferTextureBinding,
 | 
			
		||||
                            ResourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding(),
 | 
			
		||||
                            1,
 | 
			
		||||
                            new[] { vertexIndex },
 | 
			
		||||
                            new[] { this.IAdd(baseVertex, Const(index)) });
 | 
			
		||||
 
 | 
			
		||||
@@ -618,12 +618,21 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFormat format,
 | 
			
		||||
            TextureFlags flags,
 | 
			
		||||
            int binding,
 | 
			
		||||
            SetBindingPair setAndBinding,
 | 
			
		||||
            Operand[] sources)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest = Local();
 | 
			
		||||
 | 
			
		||||
            context.Add(new TextureOperation(Instruction.ImageAtomic, type, format, flags, binding, 0, new[] { dest }, sources));
 | 
			
		||||
            context.Add(new TextureOperation(
 | 
			
		||||
                Instruction.ImageAtomic,
 | 
			
		||||
                type,
 | 
			
		||||
                format,
 | 
			
		||||
                flags,
 | 
			
		||||
                setAndBinding.SetIndex,
 | 
			
		||||
                setAndBinding.Binding,
 | 
			
		||||
                0,
 | 
			
		||||
                new[] { dest },
 | 
			
		||||
                sources));
 | 
			
		||||
 | 
			
		||||
            return dest;
 | 
			
		||||
        }
 | 
			
		||||
@@ -633,12 +642,21 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFormat format,
 | 
			
		||||
            TextureFlags flags,
 | 
			
		||||
            int binding,
 | 
			
		||||
            SetBindingPair setAndBinding,
 | 
			
		||||
            int compMask,
 | 
			
		||||
            Operand[] dests,
 | 
			
		||||
            Operand[] sources)
 | 
			
		||||
        {
 | 
			
		||||
            context.Add(new TextureOperation(Instruction.ImageLoad, type, format, flags, binding, compMask, dests, sources));
 | 
			
		||||
            context.Add(new TextureOperation(
 | 
			
		||||
                Instruction.ImageLoad,
 | 
			
		||||
                type,
 | 
			
		||||
                format,
 | 
			
		||||
                flags,
 | 
			
		||||
                setAndBinding.SetIndex,
 | 
			
		||||
                setAndBinding.Binding,
 | 
			
		||||
                compMask,
 | 
			
		||||
                dests,
 | 
			
		||||
                sources));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void ImageStore(
 | 
			
		||||
@@ -646,10 +664,19 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFormat format,
 | 
			
		||||
            TextureFlags flags,
 | 
			
		||||
            int binding,
 | 
			
		||||
            SetBindingPair setAndBinding,
 | 
			
		||||
            Operand[] sources)
 | 
			
		||||
        {
 | 
			
		||||
            context.Add(new TextureOperation(Instruction.ImageStore, type, format, flags, binding, 0, null, sources));
 | 
			
		||||
            context.Add(new TextureOperation(
 | 
			
		||||
                Instruction.ImageStore,
 | 
			
		||||
                type,
 | 
			
		||||
                format,
 | 
			
		||||
                flags,
 | 
			
		||||
                setAndBinding.SetIndex,
 | 
			
		||||
                setAndBinding.Binding,
 | 
			
		||||
                0,
 | 
			
		||||
                null,
 | 
			
		||||
                sources));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static Operand IsNan(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32)
 | 
			
		||||
@@ -718,13 +745,22 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            this EmitterContext context,
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFlags flags,
 | 
			
		||||
            int binding,
 | 
			
		||||
            SetBindingPair setAndBinding,
 | 
			
		||||
            int compIndex,
 | 
			
		||||
            Operand[] sources)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest = Local();
 | 
			
		||||
 | 
			
		||||
            context.Add(new TextureOperation(Instruction.Lod, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
 | 
			
		||||
            context.Add(new TextureOperation(
 | 
			
		||||
                Instruction.Lod,
 | 
			
		||||
                type,
 | 
			
		||||
                TextureFormat.Unknown,
 | 
			
		||||
                flags,
 | 
			
		||||
                setAndBinding.SetIndex,
 | 
			
		||||
                setAndBinding.Binding,
 | 
			
		||||
                compIndex,
 | 
			
		||||
                new[] { dest },
 | 
			
		||||
                sources));
 | 
			
		||||
 | 
			
		||||
            return dest;
 | 
			
		||||
        }
 | 
			
		||||
@@ -889,24 +925,42 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            this EmitterContext context,
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFlags flags,
 | 
			
		||||
            int binding,
 | 
			
		||||
            SetBindingPair setAndBinding,
 | 
			
		||||
            int compMask,
 | 
			
		||||
            Operand[] dests,
 | 
			
		||||
            Operand[] sources)
 | 
			
		||||
        {
 | 
			
		||||
            context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources));
 | 
			
		||||
            context.Add(new TextureOperation(
 | 
			
		||||
                Instruction.TextureSample,
 | 
			
		||||
                type,
 | 
			
		||||
                TextureFormat.Unknown,
 | 
			
		||||
                flags,
 | 
			
		||||
                setAndBinding.SetIndex,
 | 
			
		||||
                setAndBinding.Binding,
 | 
			
		||||
                compMask,
 | 
			
		||||
                dests,
 | 
			
		||||
                sources));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static Operand TextureQuerySamples(
 | 
			
		||||
            this EmitterContext context,
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFlags flags,
 | 
			
		||||
            int binding,
 | 
			
		||||
            SetBindingPair setAndBinding,
 | 
			
		||||
            Operand[] sources)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest = Local();
 | 
			
		||||
 | 
			
		||||
            context.Add(new TextureOperation(Instruction.TextureQuerySamples, type, TextureFormat.Unknown, flags, binding, 0, new[] { dest }, sources));
 | 
			
		||||
            context.Add(new TextureOperation(
 | 
			
		||||
                Instruction.TextureQuerySamples,
 | 
			
		||||
                type,
 | 
			
		||||
                TextureFormat.Unknown,
 | 
			
		||||
                flags,
 | 
			
		||||
                setAndBinding.SetIndex,
 | 
			
		||||
                setAndBinding.Binding,
 | 
			
		||||
                0,
 | 
			
		||||
                new[] { dest },
 | 
			
		||||
                sources));
 | 
			
		||||
 | 
			
		||||
            return dest;
 | 
			
		||||
        }
 | 
			
		||||
@@ -915,13 +969,22 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            this EmitterContext context,
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFlags flags,
 | 
			
		||||
            int binding,
 | 
			
		||||
            SetBindingPair setAndBinding,
 | 
			
		||||
            int compIndex,
 | 
			
		||||
            Operand[] sources)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest = Local();
 | 
			
		||||
 | 
			
		||||
            context.Add(new TextureOperation(Instruction.TextureQuerySize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
 | 
			
		||||
            context.Add(new TextureOperation(
 | 
			
		||||
                Instruction.TextureQuerySize,
 | 
			
		||||
                type,
 | 
			
		||||
                TextureFormat.Unknown,
 | 
			
		||||
                flags,
 | 
			
		||||
                setAndBinding.SetIndex,
 | 
			
		||||
                setAndBinding.Binding,
 | 
			
		||||
                compIndex,
 | 
			
		||||
                new[] { dest },
 | 
			
		||||
                sources));
 | 
			
		||||
 | 
			
		||||
            return dest;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 | 
			
		||||
 | 
			
		||||
            bool hasSampler = !texOp.Inst.IsImage();
 | 
			
		||||
 | 
			
		||||
            int textureBinding = resourceManager.GetTextureOrImageBinding(
 | 
			
		||||
            SetBindingPair textureSetAndBinding = resourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                texOp.Inst,
 | 
			
		||||
                texOp.Type,
 | 
			
		||||
                texOp.Format,
 | 
			
		||||
@@ -111,7 +111,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 | 
			
		||||
 | 
			
		||||
                texOp.InsertSource(1, samplerIndex);
 | 
			
		||||
 | 
			
		||||
                int samplerBinding = resourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                SetBindingPair samplerSetAndBinding = resourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                    texOp.Inst,
 | 
			
		||||
                    SamplerType.None,
 | 
			
		||||
                    texOp.Format,
 | 
			
		||||
@@ -120,11 +120,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 | 
			
		||||
                    TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct),
 | 
			
		||||
                    samplerPoolLength);
 | 
			
		||||
 | 
			
		||||
                texOp.TurnIntoArray(textureBinding, samplerBinding);
 | 
			
		||||
                texOp.TurnIntoArray(textureSetAndBinding, samplerSetAndBinding);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                texOp.TurnIntoArray(textureBinding);
 | 
			
		||||
                texOp.TurnIntoArray(textureSetAndBinding);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
@@ -445,7 +445,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int binding = resourceManager.GetTextureOrImageBinding(
 | 
			
		||||
            SetBindingPair setAndBinding = resourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                texOp.Inst,
 | 
			
		||||
                texOp.Type,
 | 
			
		||||
                texOp.Format,
 | 
			
		||||
@@ -453,7 +453,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 | 
			
		||||
                cbufSlot,
 | 
			
		||||
                cbufOffset);
 | 
			
		||||
 | 
			
		||||
            texOp.SetBinding(binding);
 | 
			
		||||
            texOp.SetBinding(setAndBinding);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -221,7 +221,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 | 
			
		||||
 | 
			
		||||
        private static void TurnIntoArray(ResourceManager resourceManager, TextureOperation texOp, int cbufSlot, int handleIndex, int length)
 | 
			
		||||
        {
 | 
			
		||||
            int binding = resourceManager.GetTextureOrImageBinding(
 | 
			
		||||
            SetBindingPair setAndBinding = resourceManager.GetTextureOrImageBinding(
 | 
			
		||||
                texOp.Inst,
 | 
			
		||||
                texOp.Type,
 | 
			
		||||
                texOp.Format,
 | 
			
		||||
@@ -230,7 +230,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 | 
			
		||||
                handleIndex,
 | 
			
		||||
                length);
 | 
			
		||||
 | 
			
		||||
            texOp.TurnIntoArray(binding);
 | 
			
		||||
            texOp.TurnIntoArray(setAndBinding);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,8 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
        private readonly ShaderStage _stage;
 | 
			
		||||
        private readonly string _stagePrefix;
 | 
			
		||||
 | 
			
		||||
        private readonly int[] _cbSlotToBindingMap;
 | 
			
		||||
        private readonly int[] _sbSlotToBindingMap;
 | 
			
		||||
        private readonly SetBindingPair[] _cbSlotToBindingMap;
 | 
			
		||||
        private readonly SetBindingPair[] _sbSlotToBindingMap;
 | 
			
		||||
        private uint _sbSlotWritten;
 | 
			
		||||
 | 
			
		||||
        private readonly Dictionary<int, int> _sbSlots;
 | 
			
		||||
@@ -33,6 +33,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
 | 
			
		||||
        private struct TextureMeta
 | 
			
		||||
        {
 | 
			
		||||
            public int Set;
 | 
			
		||||
            public int Binding;
 | 
			
		||||
            public bool AccurateType;
 | 
			
		||||
            public SamplerType Type;
 | 
			
		||||
@@ -64,10 +65,10 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            _stage = stage;
 | 
			
		||||
            _stagePrefix = GetShaderStagePrefix(stage);
 | 
			
		||||
 | 
			
		||||
            _cbSlotToBindingMap = new int[18];
 | 
			
		||||
            _sbSlotToBindingMap = new int[16];
 | 
			
		||||
            _cbSlotToBindingMap.AsSpan().Fill(-1);
 | 
			
		||||
            _sbSlotToBindingMap.AsSpan().Fill(-1);
 | 
			
		||||
            _cbSlotToBindingMap = new SetBindingPair[18];
 | 
			
		||||
            _sbSlotToBindingMap = new SetBindingPair[16];
 | 
			
		||||
            _cbSlotToBindingMap.AsSpan().Fill(new(-1, -1));
 | 
			
		||||
            _sbSlotToBindingMap.AsSpan().Fill(new(-1, -1));
 | 
			
		||||
 | 
			
		||||
            _sbSlots = new();
 | 
			
		||||
            _sbSlotsReverse = new();
 | 
			
		||||
@@ -146,16 +147,16 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
 | 
			
		||||
        public int GetConstantBufferBinding(int slot)
 | 
			
		||||
        {
 | 
			
		||||
            int binding = _cbSlotToBindingMap[slot];
 | 
			
		||||
            if (binding < 0)
 | 
			
		||||
            SetBindingPair setAndBinding = _cbSlotToBindingMap[slot];
 | 
			
		||||
            if (setAndBinding.Binding < 0)
 | 
			
		||||
            {
 | 
			
		||||
                binding = _gpuAccessor.CreateConstantBufferBinding(slot);
 | 
			
		||||
                _cbSlotToBindingMap[slot] = binding;
 | 
			
		||||
                setAndBinding = _gpuAccessor.CreateConstantBufferBinding(slot);
 | 
			
		||||
                _cbSlotToBindingMap[slot] = setAndBinding;
 | 
			
		||||
                string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
 | 
			
		||||
                AddNewConstantBuffer(binding, $"{_stagePrefix}_c{slotNumber}");
 | 
			
		||||
                AddNewConstantBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_c{slotNumber}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return binding;
 | 
			
		||||
            return setAndBinding.Binding;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool TryGetStorageBufferBinding(int sbCbSlot, int sbCbOffset, bool write, out int binding)
 | 
			
		||||
@@ -166,14 +167,14 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            binding = _sbSlotToBindingMap[slot];
 | 
			
		||||
            SetBindingPair setAndBinding = _sbSlotToBindingMap[slot];
 | 
			
		||||
 | 
			
		||||
            if (binding < 0)
 | 
			
		||||
            if (setAndBinding.Binding < 0)
 | 
			
		||||
            {
 | 
			
		||||
                binding = _gpuAccessor.CreateStorageBufferBinding(slot);
 | 
			
		||||
                _sbSlotToBindingMap[slot] = binding;
 | 
			
		||||
                setAndBinding = _gpuAccessor.CreateStorageBufferBinding(slot);
 | 
			
		||||
                _sbSlotToBindingMap[slot] = setAndBinding;
 | 
			
		||||
                string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
 | 
			
		||||
                AddNewStorageBuffer(binding, $"{_stagePrefix}_s{slotNumber}");
 | 
			
		||||
                AddNewStorageBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_s{slotNumber}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (write)
 | 
			
		||||
@@ -181,6 +182,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                _sbSlotWritten |= 1u << slot;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            binding = setAndBinding.Binding;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -208,7 +210,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
        {
 | 
			
		||||
            for (slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
 | 
			
		||||
            {
 | 
			
		||||
                if (_cbSlotToBindingMap[slot] == binding)
 | 
			
		||||
                if (_cbSlotToBindingMap[slot].Binding == binding)
 | 
			
		||||
                {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
@@ -218,7 +220,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int GetTextureOrImageBinding(
 | 
			
		||||
        public SetBindingPair GetTextureOrImageBinding(
 | 
			
		||||
            Instruction inst,
 | 
			
		||||
            SamplerType type,
 | 
			
		||||
            TextureFormat format,
 | 
			
		||||
@@ -240,7 +242,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                format = TextureFormat.Unknown;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int binding = GetTextureOrImageBinding(
 | 
			
		||||
            SetBindingPair setAndBinding = GetTextureOrImageBinding(
 | 
			
		||||
                cbufSlot,
 | 
			
		||||
                handle,
 | 
			
		||||
                arrayLength,
 | 
			
		||||
@@ -255,10 +257,10 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
 | 
			
		||||
            _gpuAccessor.RegisterTexture(handle, cbufSlot);
 | 
			
		||||
 | 
			
		||||
            return binding;
 | 
			
		||||
            return setAndBinding;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private int GetTextureOrImageBinding(
 | 
			
		||||
        private SetBindingPair GetTextureOrImageBinding(
 | 
			
		||||
            int cbufSlot,
 | 
			
		||||
            int handle,
 | 
			
		||||
            int arrayLength,
 | 
			
		||||
@@ -311,21 +313,38 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                UsageFlags = usageFlags,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            int setIndex;
 | 
			
		||||
            int binding;
 | 
			
		||||
 | 
			
		||||
            if (dict.TryGetValue(info, out var existingMeta))
 | 
			
		||||
            {
 | 
			
		||||
                dict[info] = MergeTextureMeta(meta, existingMeta);
 | 
			
		||||
                setIndex = existingMeta.Set;
 | 
			
		||||
                binding = existingMeta.Binding;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer;
 | 
			
		||||
                if (arrayLength > 1 && (setIndex = _gpuAccessor.CreateExtraSet()) >= 0)
 | 
			
		||||
                {
 | 
			
		||||
                    // We reserved an "extra set" for the array.
 | 
			
		||||
                    // In this case the binding is always the first one (0).
 | 
			
		||||
                    // Using separate sets for array is better as we need to do less descriptor set updates.
 | 
			
		||||
 | 
			
		||||
                binding = isImage
 | 
			
		||||
                    ? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer)
 | 
			
		||||
                    : _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer);
 | 
			
		||||
                    binding = 0;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer;
 | 
			
		||||
 | 
			
		||||
                    SetBindingPair setAndBinding = isImage
 | 
			
		||||
                        ? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer)
 | 
			
		||||
                        : _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer);
 | 
			
		||||
 | 
			
		||||
                    setIndex = setAndBinding.SetIndex;
 | 
			
		||||
                    binding = setAndBinding.Binding;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                meta.Set = setIndex;
 | 
			
		||||
                meta.Binding = binding;
 | 
			
		||||
 | 
			
		||||
                dict.Add(info, meta);
 | 
			
		||||
@@ -355,7 +374,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var definition = new TextureDefinition(
 | 
			
		||||
                isImage ? 3 : 2,
 | 
			
		||||
                setIndex,
 | 
			
		||||
                binding,
 | 
			
		||||
                arrayLength,
 | 
			
		||||
                separate,
 | 
			
		||||
@@ -373,11 +392,12 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                Properties.AddOrUpdateTexture(definition);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return binding;
 | 
			
		||||
            return new SetBindingPair(setIndex, binding);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta)
 | 
			
		||||
        {
 | 
			
		||||
            meta.Set = existingMeta.Set;
 | 
			
		||||
            meta.Binding = existingMeta.Binding;
 | 
			
		||||
            meta.UsageFlags |= existingMeta.UsageFlags;
 | 
			
		||||
 | 
			
		||||
@@ -440,11 +460,11 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
 | 
			
		||||
            for (int slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
 | 
			
		||||
            {
 | 
			
		||||
                int binding = _cbSlotToBindingMap[slot];
 | 
			
		||||
                SetBindingPair setAndBinding = _cbSlotToBindingMap[slot];
 | 
			
		||||
 | 
			
		||||
                if (binding >= 0 && _usedConstantBufferBindings.Contains(binding))
 | 
			
		||||
                if (setAndBinding.Binding >= 0 && _usedConstantBufferBindings.Contains(setAndBinding.Binding))
 | 
			
		||||
                {
 | 
			
		||||
                    descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot);
 | 
			
		||||
                    descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -464,13 +484,13 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
 | 
			
		||||
            foreach ((int key, int slot) in _sbSlots)
 | 
			
		||||
            {
 | 
			
		||||
                int binding = _sbSlotToBindingMap[slot];
 | 
			
		||||
                SetBindingPair setAndBinding = _sbSlotToBindingMap[slot];
 | 
			
		||||
 | 
			
		||||
                if (binding >= 0)
 | 
			
		||||
                if (setAndBinding.Binding >= 0)
 | 
			
		||||
                {
 | 
			
		||||
                    (int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key);
 | 
			
		||||
                    BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None;
 | 
			
		||||
                    descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset, flags);
 | 
			
		||||
                    descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot, sbCbSlot, sbCbOffset, flags);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -507,6 +527,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                descriptors.Add(new TextureDescriptor(
 | 
			
		||||
                    meta.Set,
 | 
			
		||||
                    meta.Binding,
 | 
			
		||||
                    meta.Type,
 | 
			
		||||
                    info.Format,
 | 
			
		||||
@@ -527,6 +548,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    descriptors.Add(new TextureDescriptor(
 | 
			
		||||
                        meta.Set,
 | 
			
		||||
                        meta.Binding,
 | 
			
		||||
                        meta.Type,
 | 
			
		||||
                        info.Format,
 | 
			
		||||
@@ -587,24 +609,24 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddNewConstantBuffer(int binding, string name)
 | 
			
		||||
        private void AddNewConstantBuffer(int setIndex, int binding, string name)
 | 
			
		||||
        {
 | 
			
		||||
            StructureType type = new(new[]
 | 
			
		||||
            {
 | 
			
		||||
                new StructureField(AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32, "data", Constants.ConstantBufferSize / 16),
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, 0, binding, name, type));
 | 
			
		||||
            Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, setIndex, binding, name, type));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddNewStorageBuffer(int binding, string name)
 | 
			
		||||
        private void AddNewStorageBuffer(int setIndex, int binding, string name)
 | 
			
		||||
        {
 | 
			
		||||
            StructureType type = new(new[]
 | 
			
		||||
            {
 | 
			
		||||
                new StructureField(AggregateType.Array | AggregateType.U32, "data", 0),
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, 1, binding, name, type));
 | 
			
		||||
            Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, setIndex, binding, name, type));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static string GetShaderStagePrefix(ShaderStage stage)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,8 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
 | 
			
		||||
        public const int MaxVertexBufferTextures = 32;
 | 
			
		||||
 | 
			
		||||
        private const int TextureSetIndex = 2; // TODO: Get from GPU accessor.
 | 
			
		||||
 | 
			
		||||
        public int VertexInfoConstantBufferBinding { get; }
 | 
			
		||||
        public int VertexOutputStorageBufferBinding { get; }
 | 
			
		||||
        public int GeometryVertexOutputStorageBufferBinding { get; }
 | 
			
		||||
@@ -163,6 +165,21 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
            return _vertexBufferTextureBaseBinding + vaLocation;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public SetBindingPair GetVertexBufferTextureSetAndBinding(int vaLocation)
 | 
			
		||||
        {
 | 
			
		||||
            return new SetBindingPair(TextureSetIndex, GetVertexBufferTextureBinding(vaLocation));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public SetBindingPair GetIndexBufferTextureSetAndBinding()
 | 
			
		||||
        {
 | 
			
		||||
            return new SetBindingPair(TextureSetIndex, IndexBufferTextureBinding);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public SetBindingPair GetTopologyRemapBufferTextureSetAndBinding()
 | 
			
		||||
        {
 | 
			
		||||
            return new SetBindingPair(TextureSetIndex, TopologyRemapBufferTextureBinding);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal bool TryGetOffset(StorageKind storageKind, int location, int component, out int offset)
 | 
			
		||||
        {
 | 
			
		||||
            return _offsets.TryGetValue(new IoDefinition(storageKind, IoVariable.UserDefined, location, component), out offset);
 | 
			
		||||
 
 | 
			
		||||
@@ -182,6 +182,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                    texOp.Type,
 | 
			
		||||
                    texOp.Format,
 | 
			
		||||
                    texOp.Flags,
 | 
			
		||||
                    texOp.Set,
 | 
			
		||||
                    texOp.Binding,
 | 
			
		||||
                    index,
 | 
			
		||||
                    new[] { coordSize },
 | 
			
		||||
@@ -251,6 +252,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                    texOp.Type,
 | 
			
		||||
                    texOp.Format,
 | 
			
		||||
                    texOp.Flags,
 | 
			
		||||
                    texOp.Set,
 | 
			
		||||
                    texOp.Binding,
 | 
			
		||||
                    index,
 | 
			
		||||
                    new[] { coordSize },
 | 
			
		||||
@@ -471,6 +473,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                        texOp.Type,
 | 
			
		||||
                        texOp.Format,
 | 
			
		||||
                        texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
 | 
			
		||||
                        texOp.Set,
 | 
			
		||||
                        texOp.Binding,
 | 
			
		||||
                        1 << 3, // W component: i=0, j=0
 | 
			
		||||
                        new[] { dests[destIndex++] },
 | 
			
		||||
@@ -527,6 +530,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                    texOp.Type,
 | 
			
		||||
                    texOp.Format,
 | 
			
		||||
                    texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
 | 
			
		||||
                    texOp.Set,
 | 
			
		||||
                    texOp.Binding,
 | 
			
		||||
                    componentIndex,
 | 
			
		||||
                    dests,
 | 
			
		||||
@@ -573,6 +577,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                    texOp.Type,
 | 
			
		||||
                    texOp.Format,
 | 
			
		||||
                    texOp.Flags,
 | 
			
		||||
                    texOp.Set,
 | 
			
		||||
                    texOp.Binding,
 | 
			
		||||
                    index,
 | 
			
		||||
                    new[] { texSizes[index] },
 | 
			
		||||
@@ -603,6 +608,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                    texOp.Type,
 | 
			
		||||
                    texOp.Format,
 | 
			
		||||
                    texOp.Flags,
 | 
			
		||||
                    texOp.Set,
 | 
			
		||||
                    texOp.Binding,
 | 
			
		||||
                    0,
 | 
			
		||||
                    new[] { lod },
 | 
			
		||||
@@ -633,6 +639,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                    texOp.Type,
 | 
			
		||||
                    texOp.Format,
 | 
			
		||||
                    texOp.Flags,
 | 
			
		||||
                    texOp.Set,
 | 
			
		||||
                    texOp.Binding,
 | 
			
		||||
                    index,
 | 
			
		||||
                    new[] { texSizes[index] },
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                        {
 | 
			
		||||
                            bool needsSextNorm = context.Definitions.IsAttributePackedRgb10A2Signed(location);
 | 
			
		||||
 | 
			
		||||
                            SetBindingPair setAndBinding = context.ResourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
 | 
			
		||||
                            Operand temp = needsSextNorm ? Local() : dest;
 | 
			
		||||
                            Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, 0);
 | 
			
		||||
 | 
			
		||||
@@ -62,7 +63,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                                SamplerType.TextureBuffer,
 | 
			
		||||
                                TextureFormat.Unknown,
 | 
			
		||||
                                TextureFlags.IntCoords,
 | 
			
		||||
                                context.ResourceManager.Reservations.GetVertexBufferTextureBinding(location),
 | 
			
		||||
                                setAndBinding.SetIndex,
 | 
			
		||||
                                setAndBinding.Binding,
 | 
			
		||||
                                1 << component,
 | 
			
		||||
                                new[] { temp },
 | 
			
		||||
                                new[] { vertexElemOffset }));
 | 
			
		||||
@@ -75,6 +77,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            SetBindingPair setAndBinding = context.ResourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
 | 
			
		||||
                            Operand temp = component > 0 ? Local() : dest;
 | 
			
		||||
                            Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, component);
 | 
			
		||||
 | 
			
		||||
@@ -83,7 +86,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
 | 
			
		||||
                                SamplerType.TextureBuffer,
 | 
			
		||||
                                TextureFormat.Unknown,
 | 
			
		||||
                                TextureFlags.IntCoords,
 | 
			
		||||
                                context.ResourceManager.Reservations.GetVertexBufferTextureBinding(location),
 | 
			
		||||
                                setAndBinding.SetIndex,
 | 
			
		||||
                                setAndBinding.Binding,
 | 
			
		||||
                                1,
 | 
			
		||||
                                new[] { temp },
 | 
			
		||||
                                new[] { vertexElemOffset }));
 | 
			
		||||
 
 | 
			
		||||
@@ -412,8 +412,8 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
 | 
			
		||||
                if (Stage == ShaderStage.Vertex)
 | 
			
		||||
                {
 | 
			
		||||
                    int ibBinding = resourceManager.Reservations.IndexBufferTextureBinding;
 | 
			
		||||
                    TextureDefinition indexBuffer = new(2, ibBinding, "ib_data", SamplerType.TextureBuffer);
 | 
			
		||||
                    SetBindingPair ibSetAndBinding = resourceManager.Reservations.GetIndexBufferTextureSetAndBinding();
 | 
			
		||||
                    TextureDefinition indexBuffer = new(ibSetAndBinding.SetIndex, ibSetAndBinding.Binding, "ib_data", SamplerType.TextureBuffer);
 | 
			
		||||
                    resourceManager.Properties.AddOrUpdateTexture(indexBuffer);
 | 
			
		||||
 | 
			
		||||
                    int inputMap = _program.AttributeUsage.UsedInputAttributes;
 | 
			
		||||
@@ -421,8 +421,8 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                    while (inputMap != 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        int location = BitOperations.TrailingZeroCount(inputMap);
 | 
			
		||||
                        int binding = resourceManager.Reservations.GetVertexBufferTextureBinding(location);
 | 
			
		||||
                        TextureDefinition vaBuffer = new(2, binding, $"vb_data{location}", SamplerType.TextureBuffer);
 | 
			
		||||
                        SetBindingPair setAndBinding = resourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
 | 
			
		||||
                        TextureDefinition vaBuffer = new(setAndBinding.SetIndex, setAndBinding.Binding, $"vb_data{location}", SamplerType.TextureBuffer);
 | 
			
		||||
                        resourceManager.Properties.AddOrUpdateTexture(vaBuffer);
 | 
			
		||||
 | 
			
		||||
                        inputMap &= ~(1 << location);
 | 
			
		||||
@@ -430,8 +430,8 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                }
 | 
			
		||||
                else if (Stage == ShaderStage.Geometry)
 | 
			
		||||
                {
 | 
			
		||||
                    int trbBinding = resourceManager.Reservations.TopologyRemapBufferTextureBinding;
 | 
			
		||||
                    TextureDefinition remapBuffer = new(2, trbBinding, "trb_data", SamplerType.TextureBuffer);
 | 
			
		||||
                    SetBindingPair trbSetAndBinding = resourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding();
 | 
			
		||||
                    TextureDefinition remapBuffer = new(trbSetAndBinding.SetIndex, trbSetAndBinding.Binding, "trb_data", SamplerType.TextureBuffer);
 | 
			
		||||
                    resourceManager.Properties.AddOrUpdateTexture(remapBuffer);
 | 
			
		||||
 | 
			
		||||
                    int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding;
 | 
			
		||||
 
 | 
			
		||||
@@ -69,17 +69,7 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private record struct ArrayRef<T>
 | 
			
		||||
        {
 | 
			
		||||
            public ShaderStage Stage;
 | 
			
		||||
            public T Array;
 | 
			
		||||
 | 
			
		||||
            public ArrayRef(ShaderStage stage, T array)
 | 
			
		||||
            {
 | 
			
		||||
                Stage = stage;
 | 
			
		||||
                Array = array;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        private readonly record struct ArrayRef<T>(ShaderStage Stage, T Array);
 | 
			
		||||
 | 
			
		||||
        private readonly VulkanRenderer _gd;
 | 
			
		||||
        private readonly Device _device;
 | 
			
		||||
@@ -97,6 +87,9 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        private ArrayRef<TextureArray>[] _textureArrayRefs;
 | 
			
		||||
        private ArrayRef<ImageArray>[] _imageArrayRefs;
 | 
			
		||||
 | 
			
		||||
        private ArrayRef<TextureArray>[] _textureArrayExtraRefs;
 | 
			
		||||
        private ArrayRef<ImageArray>[] _imageArrayExtraRefs;
 | 
			
		||||
 | 
			
		||||
        private readonly DescriptorBufferInfo[] _uniformBuffers;
 | 
			
		||||
        private readonly DescriptorBufferInfo[] _storageBuffers;
 | 
			
		||||
        private readonly DescriptorImageInfo[] _textures;
 | 
			
		||||
@@ -152,6 +145,9 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            _textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
 | 
			
		||||
            _imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
 | 
			
		||||
 | 
			
		||||
            _textureArrayExtraRefs = Array.Empty<ArrayRef<TextureArray>>();
 | 
			
		||||
            _imageArrayExtraRefs = Array.Empty<ArrayRef<ImageArray>>();
 | 
			
		||||
 | 
			
		||||
            _uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings];
 | 
			
		||||
            _storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings];
 | 
			
		||||
            _textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage];
 | 
			
		||||
@@ -495,25 +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<TextureArray> 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<TextureArray>(stage, array as TextureArray);
 | 
			
		||||
                arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
 | 
			
		||||
 | 
			
		||||
                SignalDirty(DirtyFlags.Texture);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetTextureArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, ITextureArray array)
 | 
			
		||||
        {
 | 
			
		||||
            ref ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _textureArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
 | 
			
		||||
 | 
			
		||||
            if (arrayRef.Stage != stage || arrayRef.Array != array)
 | 
			
		||||
            {
 | 
			
		||||
                arrayRef.Array?.DecrementBindCount();
 | 
			
		||||
 | 
			
		||||
                if (array is TextureArray textureArray)
 | 
			
		||||
                {
 | 
			
		||||
                    textureArray.IncrementBindCount();
 | 
			
		||||
                    textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
 | 
			
		||||
 | 
			
		||||
                SignalDirty(DirtyFlags.Texture);
 | 
			
		||||
            }
 | 
			
		||||
@@ -521,30 +531,56 @@ 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);
 | 
			
		||||
            }
 | 
			
		||||
            ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayRefs, binding, ArrayGrowthSize);
 | 
			
		||||
 | 
			
		||||
            if (_imageArrayRefs[binding].Stage != stage || _imageArrayRefs[binding].Array != array)
 | 
			
		||||
            if (arrayRef.Stage != stage || arrayRef.Array != array)
 | 
			
		||||
            {
 | 
			
		||||
                if (_imageArrayRefs[binding].Array != null)
 | 
			
		||||
                {
 | 
			
		||||
                    _imageArrayRefs[binding].Array.Bound = false;
 | 
			
		||||
                }
 | 
			
		||||
                arrayRef.Array?.DecrementBindCount();
 | 
			
		||||
 | 
			
		||||
                if (array is ImageArray imageArray)
 | 
			
		||||
                {
 | 
			
		||||
                    imageArray.Bound = true;
 | 
			
		||||
                    imageArray.IncrementBindCount();
 | 
			
		||||
                    imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                _imageArrayRefs[binding] = new ArrayRef<ImageArray>(stage, array as ImageArray);
 | 
			
		||||
                arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
 | 
			
		||||
 | 
			
		||||
                SignalDirty(DirtyFlags.Image);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImageArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, IImageArray array)
 | 
			
		||||
        {
 | 
			
		||||
            ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
 | 
			
		||||
 | 
			
		||||
            if (arrayRef.Stage != stage || arrayRef.Array != array)
 | 
			
		||||
            {
 | 
			
		||||
                arrayRef.Array?.DecrementBindCount();
 | 
			
		||||
 | 
			
		||||
                if (array is ImageArray imageArray)
 | 
			
		||||
                {
 | 
			
		||||
                    imageArray.IncrementBindCount();
 | 
			
		||||
                    imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
 | 
			
		||||
 | 
			
		||||
                SignalDirty(DirtyFlags.Image);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static ref ArrayRef<T> GetArrayRef<T>(ref ArrayRef<T>[] array, int index, int growthSize = 1)
 | 
			
		||||
        {
 | 
			
		||||
            ArgumentOutOfRangeException.ThrowIfNegative(index);
 | 
			
		||||
 | 
			
		||||
            if (array.Length <= index)
 | 
			
		||||
            {
 | 
			
		||||
                Array.Resize(ref array, index + growthSize);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ref array[index];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < buffers.Length; i++)
 | 
			
		||||
@@ -594,31 +630,40 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var program = _program;
 | 
			
		||||
 | 
			
		||||
            if (_dirty.HasFlag(DirtyFlags.Uniform))
 | 
			
		||||
            {
 | 
			
		||||
                if (_program.UsePushDescriptors)
 | 
			
		||||
                if (program.UsePushDescriptors)
 | 
			
		||||
                {
 | 
			
		||||
                    UpdateAndBindUniformBufferPd(cbs, pbp);
 | 
			
		||||
                    UpdateAndBindUniformBufferPd(cbs);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    UpdateAndBind(cbs, PipelineBase.UniformSetIndex, pbp);
 | 
			
		||||
                    UpdateAndBind(cbs, program, PipelineBase.UniformSetIndex, pbp);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (_dirty.HasFlag(DirtyFlags.Storage))
 | 
			
		||||
            {
 | 
			
		||||
                UpdateAndBind(cbs, PipelineBase.StorageSetIndex, pbp);
 | 
			
		||||
                UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (_dirty.HasFlag(DirtyFlags.Texture))
 | 
			
		||||
            {
 | 
			
		||||
                UpdateAndBind(cbs, PipelineBase.TextureSetIndex, pbp);
 | 
			
		||||
                UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (_dirty.HasFlag(DirtyFlags.Image))
 | 
			
		||||
            {
 | 
			
		||||
                UpdateAndBind(cbs, PipelineBase.ImageSetIndex, pbp);
 | 
			
		||||
                UpdateAndBind(cbs, program, PipelineBase.ImageSetIndex, pbp);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (program.BindingSegments.Length > PipelineBase.DescriptorSetLayouts)
 | 
			
		||||
            {
 | 
			
		||||
                // Program is using extra sets, we need to bind those too.
 | 
			
		||||
 | 
			
		||||
                BindExtraSets(cbs, program, pbp);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _dirty = DirtyFlags.None;
 | 
			
		||||
@@ -658,9 +703,8 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
        private void UpdateAndBind(CommandBufferScoped cbs, int setIndex, PipelineBindPoint pbp)
 | 
			
		||||
        private void UpdateAndBind(CommandBufferScoped cbs, ShaderCollection program, int setIndex, PipelineBindPoint pbp)
 | 
			
		||||
        {
 | 
			
		||||
            var program = _program;
 | 
			
		||||
            var bindingSegments = program.BindingSegments[setIndex];
 | 
			
		||||
 | 
			
		||||
            if (bindingSegments.Length == 0)
 | 
			
		||||
@@ -869,7 +913,7 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
        private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs, PipelineBindPoint pbp)
 | 
			
		||||
        private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs)
 | 
			
		||||
        {
 | 
			
		||||
            int sequence = _pdSequence;
 | 
			
		||||
            var bindingSegments = _program.BindingSegments[PipelineBase.UniformSetIndex];
 | 
			
		||||
@@ -933,6 +977,56 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void BindExtraSets(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
 | 
			
		||||
        {
 | 
			
		||||
            for (int setIndex = PipelineBase.DescriptorSetLayouts; setIndex < program.BindingSegments.Length; setIndex++)
 | 
			
		||||
            {
 | 
			
		||||
                var bindingSegments = program.BindingSegments[setIndex];
 | 
			
		||||
 | 
			
		||||
                if (bindingSegments.Length == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ResourceBindingSegment segment = bindingSegments[0];
 | 
			
		||||
 | 
			
		||||
                if (segment.IsArray)
 | 
			
		||||
                {
 | 
			
		||||
                    DescriptorSet[] sets = null;
 | 
			
		||||
 | 
			
		||||
                    if (segment.Type == ResourceType.Texture ||
 | 
			
		||||
                        segment.Type == ResourceType.Sampler ||
 | 
			
		||||
                        segment.Type == ResourceType.TextureAndSampler ||
 | 
			
		||||
                        segment.Type == ResourceType.BufferTexture)
 | 
			
		||||
                    {
 | 
			
		||||
                        sets = _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
 | 
			
		||||
                            _device,
 | 
			
		||||
                            cbs,
 | 
			
		||||
                            _templateUpdater,
 | 
			
		||||
                            program,
 | 
			
		||||
                            setIndex,
 | 
			
		||||
                            _dummyTexture,
 | 
			
		||||
                            _dummySampler);
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage)
 | 
			
		||||
                    {
 | 
			
		||||
                        sets = _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
 | 
			
		||||
                            _device,
 | 
			
		||||
                            cbs,
 | 
			
		||||
                            _templateUpdater,
 | 
			
		||||
                            program,
 | 
			
		||||
                            setIndex,
 | 
			
		||||
                            _dummyTexture);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (sets != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SignalCommandBufferChange()
 | 
			
		||||
        {
 | 
			
		||||
            _updateDescriptorCacheCbIndex = true;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL;
 | 
			
		||||
using Silk.NET.Vulkan;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
{
 | 
			
		||||
@@ -24,12 +25,18 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
 | 
			
		||||
        private HashSet<TextureStorage> _storages;
 | 
			
		||||
 | 
			
		||||
        private DescriptorSet[] _cachedDescriptorSets;
 | 
			
		||||
 | 
			
		||||
        private int _cachedCommandBufferIndex;
 | 
			
		||||
        private int _cachedSubmissionCount;
 | 
			
		||||
 | 
			
		||||
        private ShaderCollection _cachedDscProgram;
 | 
			
		||||
        private int _cachedDscSetIndex;
 | 
			
		||||
        private int _cachedDscIndex;
 | 
			
		||||
 | 
			
		||||
        private readonly bool _isBuffer;
 | 
			
		||||
 | 
			
		||||
        public bool Bound;
 | 
			
		||||
        private int _bindCount;
 | 
			
		||||
 | 
			
		||||
        public ImageArray(VulkanRenderer gd, int size, bool isBuffer)
 | 
			
		||||
        {
 | 
			
		||||
@@ -97,8 +104,12 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        {
 | 
			
		||||
            _cachedCommandBufferIndex = -1;
 | 
			
		||||
            _storages = null;
 | 
			
		||||
            _cachedDescriptorSets = null;
 | 
			
		||||
 | 
			
		||||
            _gd.PipelineInternal.ForceImageDirty();
 | 
			
		||||
            if (_bindCount != 0)
 | 
			
		||||
            {
 | 
			
		||||
                _gd.PipelineInternal.ForceImageDirty();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
 | 
			
		||||
@@ -175,5 +186,65 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
 | 
			
		||||
            return bufferTextures;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DescriptorSet[] GetDescriptorSets(
 | 
			
		||||
            Device device,
 | 
			
		||||
            CommandBufferScoped cbs,
 | 
			
		||||
            DescriptorSetTemplateUpdater templateUpdater,
 | 
			
		||||
            ShaderCollection program,
 | 
			
		||||
            int setIndex,
 | 
			
		||||
            TextureView dummyTexture)
 | 
			
		||||
        {
 | 
			
		||||
            if (_cachedDescriptorSets != null)
 | 
			
		||||
            {
 | 
			
		||||
                // We still need to ensure the current command buffer holds a reference to all used textures.
 | 
			
		||||
 | 
			
		||||
                if (!_isBuffer)
 | 
			
		||||
                {
 | 
			
		||||
                    GetImageInfos(_gd, cbs, dummyTexture);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    GetBufferViews(cbs);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return _cachedDescriptorSets;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _cachedDscProgram?.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
 | 
			
		||||
            var dsc = program.GetNewManualDescriptorSetCollection(cbs.CommandBufferIndex, setIndex, out _cachedDscIndex).Get(cbs);
 | 
			
		||||
 | 
			
		||||
            DescriptorSetTemplate template = program.Templates[setIndex];
 | 
			
		||||
 | 
			
		||||
            DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
 | 
			
		||||
 | 
			
		||||
            if (!_isBuffer)
 | 
			
		||||
            {
 | 
			
		||||
                tu.Push(GetImageInfos(_gd, cbs, dummyTexture));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                tu.Push(GetBufferViews(cbs));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var sets = dsc.GetSets();
 | 
			
		||||
            templateUpdater.Commit(_gd, device, sets[0]);
 | 
			
		||||
            _cachedDescriptorSets = sets;
 | 
			
		||||
            _cachedDscProgram = program;
 | 
			
		||||
            _cachedDscSetIndex = setIndex;
 | 
			
		||||
 | 
			
		||||
            return sets;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void IncrementBindCount()
 | 
			
		||||
        {
 | 
			
		||||
            _bindCount++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void DecrementBindCount()
 | 
			
		||||
        {
 | 
			
		||||
            int newBindCount = --_bindCount;
 | 
			
		||||
            Debug.Assert(newBindCount >= 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,6 +901,11 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            _descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
 | 
			
		||||
        {
 | 
			
		||||
            _descriptorSetUpdater.SetImageArraySeparate(Cbs, stage, setIndex, array);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetIndexBuffer(BufferRange buffer, IndexType type)
 | 
			
		||||
        {
 | 
			
		||||
            if (buffer.Handle != BufferHandle.Null)
 | 
			
		||||
@@ -945,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.
 | 
			
		||||
@@ -955,7 +957,6 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        {
 | 
			
		||||
            // TODO.
 | 
			
		||||
        }
 | 
			
		||||
#pragma warning restore CA1822
 | 
			
		||||
 | 
			
		||||
        public void SetPrimitiveRestart(bool enable, int index)
 | 
			
		||||
        {
 | 
			
		||||
@@ -1156,6 +1157,11 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            _descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
 | 
			
		||||
        {
 | 
			
		||||
            _descriptorSetUpdater.SetTextureArraySeparate(Cbs, stage, setIndex, array);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
 | 
			
		||||
        {
 | 
			
		||||
            PauseTransformFeedbackInternal();
 | 
			
		||||
@@ -1186,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<VertexAttribDescriptor> vertexAttribs)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ using Silk.NET.Vulkan;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.ObjectModel;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
{
 | 
			
		||||
@@ -27,6 +28,24 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        private int _dsLastCbIndex;
 | 
			
		||||
        private int _dsLastSubmissionCount;
 | 
			
		||||
 | 
			
		||||
        private struct ManualDescriptorSetEntry
 | 
			
		||||
        {
 | 
			
		||||
            public Auto<DescriptorSetCollection> DescriptorSet;
 | 
			
		||||
            public int CbIndex;
 | 
			
		||||
            public int CbSubmissionCount;
 | 
			
		||||
            public bool InUse;
 | 
			
		||||
 | 
			
		||||
            public ManualDescriptorSetEntry(Auto<DescriptorSetCollection> descriptorSet, int cbIndex, int cbSubmissionCount, bool inUse)
 | 
			
		||||
            {
 | 
			
		||||
                DescriptorSet = descriptorSet;
 | 
			
		||||
                CbIndex = cbIndex;
 | 
			
		||||
                CbSubmissionCount = cbSubmissionCount;
 | 
			
		||||
                InUse = inUse;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private readonly List<ManualDescriptorSetEntry>[] _manualDsCache;
 | 
			
		||||
 | 
			
		||||
        private readonly Dictionary<long, DescriptorSetTemplate> _pdTemplates;
 | 
			
		||||
        private readonly ResourceDescriptorCollection _pdDescriptors;
 | 
			
		||||
        private long _lastPdUsage;
 | 
			
		||||
@@ -50,6 +69,7 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _dsCacheCursor = new int[setsCount];
 | 
			
		||||
            _manualDsCache = new List<ManualDescriptorSetEntry>[setsCount];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public PipelineLayoutCacheEntry(
 | 
			
		||||
@@ -124,6 +144,51 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            return list[index];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex)
 | 
			
		||||
        {
 | 
			
		||||
            int submissionCount = _gd.CommandBufferPool.GetSubmissionCount(commandBufferIndex);
 | 
			
		||||
 | 
			
		||||
            var list = _manualDsCache[setIndex] ??= new();
 | 
			
		||||
            var span = CollectionsMarshal.AsSpan(list);
 | 
			
		||||
 | 
			
		||||
            for (int index = 0; index < span.Length; index++)
 | 
			
		||||
            {
 | 
			
		||||
                ref ManualDescriptorSetEntry entry = ref span[index];
 | 
			
		||||
 | 
			
		||||
                if (!entry.InUse && (entry.CbIndex != commandBufferIndex || entry.CbSubmissionCount != submissionCount))
 | 
			
		||||
                {
 | 
			
		||||
                    entry.InUse = true;
 | 
			
		||||
                    entry.CbIndex = commandBufferIndex;
 | 
			
		||||
                    entry.CbSubmissionCount = submissionCount;
 | 
			
		||||
 | 
			
		||||
                    cacheIndex = index;
 | 
			
		||||
 | 
			
		||||
                    return entry.DescriptorSet;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var dsc = _descriptorSetManager.AllocateDescriptorSet(
 | 
			
		||||
                _gd.Api,
 | 
			
		||||
                DescriptorSetLayouts[setIndex],
 | 
			
		||||
                _poolSizes[setIndex],
 | 
			
		||||
                setIndex,
 | 
			
		||||
                _consumedDescriptorsPerSet[setIndex],
 | 
			
		||||
                false);
 | 
			
		||||
 | 
			
		||||
            cacheIndex = list.Count;
 | 
			
		||||
            list.Add(new ManualDescriptorSetEntry(dsc, commandBufferIndex, submissionCount, inUse: true));
 | 
			
		||||
 | 
			
		||||
            return dsc;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)
 | 
			
		||||
        {
 | 
			
		||||
            var list = _manualDsCache[setIndex];
 | 
			
		||||
            var span = CollectionsMarshal.AsSpan(list);
 | 
			
		||||
 | 
			
		||||
            span[cacheIndex].InUse = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static Span<DescriptorPoolSize> GetDescriptorPoolSizes(Span<DescriptorPoolSize> output, ResourceDescriptorCollection setDescriptor, uint multiplier)
 | 
			
		||||
        {
 | 
			
		||||
            int count = 0;
 | 
			
		||||
@@ -204,6 +269,21 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                for (int i = 0; i < _manualDsCache.Length; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    if (_manualDsCache[i] == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    for (int j = 0; j < _manualDsCache[i].Count; j++)
 | 
			
		||||
                    {
 | 
			
		||||
                        _manualDsCache[i][j].DescriptorSet.Dispose();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    _manualDsCache[i].Clear();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                _gd.Api.DestroyPipelineLayout(_device, PipelineLayout, null);
 | 
			
		||||
 | 
			
		||||
                for (int i = 0; i < DescriptorSetLayouts.Length; i++)
 | 
			
		||||
 
 | 
			
		||||
@@ -604,6 +604,16 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            return _plce.GetNewDescriptorSetCollection(setIndex, out isNew);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex)
 | 
			
		||||
        {
 | 
			
		||||
            return _plce.GetNewManualDescriptorSetCollection(commandBufferIndex, setIndex, out cacheIndex);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)
 | 
			
		||||
        {
 | 
			
		||||
            _plce.ReleaseManualDescriptorSetCollection(setIndex, cacheIndex);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool HasSameLayout(ShaderCollection other)
 | 
			
		||||
        {
 | 
			
		||||
            return other != null && _plce == other._plce;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL;
 | 
			
		||||
using Silk.NET.Vulkan;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
{
 | 
			
		||||
@@ -24,12 +25,18 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
 | 
			
		||||
        private HashSet<TextureStorage> _storages;
 | 
			
		||||
 | 
			
		||||
        private DescriptorSet[] _cachedDescriptorSets;
 | 
			
		||||
 | 
			
		||||
        private int _cachedCommandBufferIndex;
 | 
			
		||||
        private int _cachedSubmissionCount;
 | 
			
		||||
 | 
			
		||||
        private ShaderCollection _cachedDscProgram;
 | 
			
		||||
        private int _cachedDscSetIndex;
 | 
			
		||||
        private int _cachedDscIndex;
 | 
			
		||||
 | 
			
		||||
        private readonly bool _isBuffer;
 | 
			
		||||
 | 
			
		||||
        public bool Bound;
 | 
			
		||||
        private int _bindCount;
 | 
			
		||||
 | 
			
		||||
        public TextureArray(VulkanRenderer gd, int size, bool isBuffer)
 | 
			
		||||
        {
 | 
			
		||||
@@ -106,8 +113,12 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        {
 | 
			
		||||
            _cachedCommandBufferIndex = -1;
 | 
			
		||||
            _storages = null;
 | 
			
		||||
            _cachedDescriptorSets = null;
 | 
			
		||||
 | 
			
		||||
            _gd.PipelineInternal.ForceTextureDirty();
 | 
			
		||||
            if (_bindCount != 0)
 | 
			
		||||
            {
 | 
			
		||||
                _gd.PipelineInternal.ForceTextureDirty();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
 | 
			
		||||
@@ -190,5 +201,66 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
 | 
			
		||||
            return bufferTextures;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DescriptorSet[] GetDescriptorSets(
 | 
			
		||||
            Device device,
 | 
			
		||||
            CommandBufferScoped cbs,
 | 
			
		||||
            DescriptorSetTemplateUpdater templateUpdater,
 | 
			
		||||
            ShaderCollection program,
 | 
			
		||||
            int setIndex,
 | 
			
		||||
            TextureView dummyTexture,
 | 
			
		||||
            SamplerHolder dummySampler)
 | 
			
		||||
        {
 | 
			
		||||
            if (_cachedDescriptorSets != null)
 | 
			
		||||
            {
 | 
			
		||||
                // We still need to ensure the current command buffer holds a reference to all used textures.
 | 
			
		||||
 | 
			
		||||
                if (!_isBuffer)
 | 
			
		||||
                {
 | 
			
		||||
                    GetImageInfos(_gd, cbs, dummyTexture, dummySampler);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    GetBufferViews(cbs);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return _cachedDescriptorSets;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _cachedDscProgram?.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
 | 
			
		||||
            var dsc = program.GetNewManualDescriptorSetCollection(cbs.CommandBufferIndex, setIndex, out _cachedDscIndex).Get(cbs);
 | 
			
		||||
 | 
			
		||||
            DescriptorSetTemplate template = program.Templates[setIndex];
 | 
			
		||||
 | 
			
		||||
            DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
 | 
			
		||||
 | 
			
		||||
            if (!_isBuffer)
 | 
			
		||||
            {
 | 
			
		||||
                tu.Push(GetImageInfos(_gd, cbs, dummyTexture, dummySampler));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                tu.Push(GetBufferViews(cbs));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var sets = dsc.GetSets();
 | 
			
		||||
            templateUpdater.Commit(_gd, device, sets[0]);
 | 
			
		||||
            _cachedDescriptorSets = sets;
 | 
			
		||||
            _cachedDscProgram = program;
 | 
			
		||||
            _cachedDscSetIndex = setIndex;
 | 
			
		||||
 | 
			
		||||
            return sets;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void IncrementBindCount()
 | 
			
		||||
        {
 | 
			
		||||
            _bindCount++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void DecrementBindCount()
 | 
			
		||||
        {
 | 
			
		||||
            int newBindCount = --_bindCount;
 | 
			
		||||
            Debug.Assert(newBindCount >= 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -728,6 +728,12 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
                supportsViewportSwizzle: false,
 | 
			
		||||
                supportsIndirectParameters: true,
 | 
			
		||||
                supportsDepthClipControl: Capabilities.SupportsDepthClipControl,
 | 
			
		||||
                uniformBufferSetIndex: PipelineBase.UniformSetIndex,
 | 
			
		||||
                storageBufferSetIndex: PipelineBase.StorageSetIndex,
 | 
			
		||||
                textureSetIndex: PipelineBase.TextureSetIndex,
 | 
			
		||||
                imageSetIndex: PipelineBase.ImageSetIndex,
 | 
			
		||||
                extraSetBaseIndex: PipelineBase.DescriptorSetLayouts,
 | 
			
		||||
                maximumExtraSets: Math.Max(0, (int)limits.MaxBoundDescriptorSets - PipelineBase.DescriptorSetLayouts),
 | 
			
		||||
                maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
 | 
			
		||||
                maximumStorageBuffersPerStage: Constants.MaxStorageBuffersPerStage,
 | 
			
		||||
                maximumTexturesPerStage: Constants.MaxTexturesPerStage,
 | 
			
		||||
 
 | 
			
		||||
@@ -25,32 +25,32 @@ namespace Ryujinx.ShaderTools
 | 
			
		||||
                _imagesCount = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public int CreateConstantBufferBinding(int index)
 | 
			
		||||
            public SetBindingPair CreateConstantBufferBinding(int index)
 | 
			
		||||
            {
 | 
			
		||||
                return index + 1;
 | 
			
		||||
                return new SetBindingPair(0, index + 1);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public int CreateImageBinding(int count, bool isBuffer)
 | 
			
		||||
            public SetBindingPair CreateImageBinding(int count, bool isBuffer)
 | 
			
		||||
            {
 | 
			
		||||
                int binding = _imagesCount;
 | 
			
		||||
 | 
			
		||||
                _imagesCount += count;
 | 
			
		||||
 | 
			
		||||
                return binding;
 | 
			
		||||
                return new SetBindingPair(3, binding);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public int CreateStorageBufferBinding(int index)
 | 
			
		||||
            public SetBindingPair CreateStorageBufferBinding(int index)
 | 
			
		||||
            {
 | 
			
		||||
                return index;
 | 
			
		||||
                return new SetBindingPair(1, index);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public int CreateTextureBinding(int count, bool isBuffer)
 | 
			
		||||
            public SetBindingPair CreateTextureBinding(int count, bool isBuffer)
 | 
			
		||||
            {
 | 
			
		||||
                int binding = _texturesCount;
 | 
			
		||||
 | 
			
		||||
                _texturesCount += count;
 | 
			
		||||
 | 
			
		||||
                return binding;
 | 
			
		||||
                return new SetBindingPair(2, binding);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user