mirror of
				https://github.com/ryujinx-mirror/ryujinx.git
				synced 2025-11-04 08:59:04 -06:00 
			
		
		
		
	Change image format view handling to allow view incompatible formats (#7311)
* Allow creating texture aliases on texture pool * Delete old image format override code * New format incompatible alias * Missing bounds check * GetForBinding now takes FormatInfo * Make FormatInfo struct more compact
This commit is contained in:
		@@ -4,7 +4,6 @@ namespace Ryujinx.Graphics.GAL
 | 
			
		||||
{
 | 
			
		||||
    public interface IImageArray : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        void SetFormats(int index, Format[] imageFormats);
 | 
			
		||||
        void SetImages(int index, ITexture[] images);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.GAL
 | 
			
		||||
 | 
			
		||||
        void SetIndexBuffer(BufferRange buffer, IndexType type);
 | 
			
		||||
 | 
			
		||||
        void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat);
 | 
			
		||||
        void SetImage(ShaderStage stage, int binding, ITexture texture);
 | 
			
		||||
        void SetImageArray(ShaderStage stage, int binding, IImageArray array);
 | 
			
		||||
        void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
 | 
			
		||||
            Register<CounterEventFlushCommand>(CommandType.CounterEventFlush);
 | 
			
		||||
 | 
			
		||||
            Register<ImageArrayDisposeCommand>(CommandType.ImageArrayDispose);
 | 
			
		||||
            Register<ImageArraySetFormatsCommand>(CommandType.ImageArraySetFormats);
 | 
			
		||||
            Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages);
 | 
			
		||||
 | 
			
		||||
            Register<ProgramDisposeCommand>(CommandType.ProgramDispose);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
 | 
			
		||||
        CounterEventFlush,
 | 
			
		||||
 | 
			
		||||
        ImageArrayDispose,
 | 
			
		||||
        ImageArraySetFormats,
 | 
			
		||||
        ImageArraySetImages,
 | 
			
		||||
 | 
			
		||||
        ProgramDispose,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
using Ryujinx.Graphics.GAL.Multithreading.Model;
 | 
			
		||||
using Ryujinx.Graphics.GAL.Multithreading.Resources;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray
 | 
			
		||||
{
 | 
			
		||||
    struct ImageArraySetFormatsCommand : IGALCommand, IGALCommand<ImageArraySetFormatsCommand>
 | 
			
		||||
    {
 | 
			
		||||
        public readonly CommandType CommandType => CommandType.ImageArraySetFormats;
 | 
			
		||||
        private TableRef<ThreadedImageArray> _imageArray;
 | 
			
		||||
        private int _index;
 | 
			
		||||
        private TableRef<Format[]> _imageFormats;
 | 
			
		||||
 | 
			
		||||
        public void Set(TableRef<ThreadedImageArray> imageArray, int index, TableRef<Format[]> imageFormats)
 | 
			
		||||
        {
 | 
			
		||||
            _imageArray = imageArray;
 | 
			
		||||
            _index = index;
 | 
			
		||||
            _imageFormats = imageFormats;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Run(ref ImageArraySetFormatsCommand command, ThreadedRenderer threaded, IRenderer renderer)
 | 
			
		||||
        {
 | 
			
		||||
            ThreadedImageArray imageArray = command._imageArray.Get(threaded);
 | 
			
		||||
            imageArray.Base.SetFormats(command._index, command._imageFormats.Get(threaded));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -10,19 +10,17 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 | 
			
		||||
        private ShaderStage _stage;
 | 
			
		||||
        private int _binding;
 | 
			
		||||
        private TableRef<ITexture> _texture;
 | 
			
		||||
        private Format _imageFormat;
 | 
			
		||||
 | 
			
		||||
        public void Set(ShaderStage stage, int binding, TableRef<ITexture> texture, Format imageFormat)
 | 
			
		||||
        public void Set(ShaderStage stage, int binding, TableRef<ITexture> texture)
 | 
			
		||||
        {
 | 
			
		||||
            _stage = stage;
 | 
			
		||||
            _binding = binding;
 | 
			
		||||
            _texture = texture;
 | 
			
		||||
            _imageFormat = imageFormat;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Run(ref SetImageCommand command, ThreadedRenderer threaded, IRenderer renderer)
 | 
			
		||||
        {
 | 
			
		||||
            renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base, command._imageFormat);
 | 
			
		||||
            renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,12 +27,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
 | 
			
		||||
            _renderer.QueueCommand();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetFormats(int index, Format[] imageFormats)
 | 
			
		||||
        {
 | 
			
		||||
            _renderer.New<ImageArraySetFormatsCommand>().Set(Ref(this), index, Ref(imageFormats));
 | 
			
		||||
            _renderer.QueueCommand();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImages(int index, ITexture[] images)
 | 
			
		||||
        {
 | 
			
		||||
            _renderer.New<ImageArraySetImagesCommand>().Set(Ref(this), index, Ref(images));
 | 
			
		||||
 
 | 
			
		||||
@@ -177,9 +177,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
 | 
			
		||||
            _renderer.QueueCommand();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat)
 | 
			
		||||
        public void SetImage(ShaderStage stage, int binding, ITexture texture)
 | 
			
		||||
        {
 | 
			
		||||
            _renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture), imageFormat);
 | 
			
		||||
            _renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture));
 | 
			
		||||
            _renderer.QueueCommand();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
using Ryujinx.Common.Logging;
 | 
			
		||||
using Ryujinx.Graphics.GAL;
 | 
			
		||||
using Ryujinx.Graphics.Gpu.Image;
 | 
			
		||||
using Ryujinx.Graphics.Shader;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Graphics.Gpu.Engine
 | 
			
		||||
@@ -61,51 +62,51 @@ namespace Ryujinx.Graphics.Gpu.Engine
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="format">Shader image format</param>
 | 
			
		||||
        /// <returns>Texture format</returns>
 | 
			
		||||
        public static Format GetFormat(TextureFormat format)
 | 
			
		||||
        public static FormatInfo GetFormatInfo(TextureFormat format)
 | 
			
		||||
        {
 | 
			
		||||
            return format switch
 | 
			
		||||
            {
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
                TextureFormat.R8Unorm           => Format.R8Unorm,
 | 
			
		||||
                TextureFormat.R8Snorm           => Format.R8Snorm,
 | 
			
		||||
                TextureFormat.R8Uint            => Format.R8Uint,
 | 
			
		||||
                TextureFormat.R8Sint            => Format.R8Sint,
 | 
			
		||||
                TextureFormat.R16Float          => Format.R16Float,
 | 
			
		||||
                TextureFormat.R16Unorm          => Format.R16Unorm,
 | 
			
		||||
                TextureFormat.R16Snorm          => Format.R16Snorm,
 | 
			
		||||
                TextureFormat.R16Uint           => Format.R16Uint,
 | 
			
		||||
                TextureFormat.R16Sint           => Format.R16Sint,
 | 
			
		||||
                TextureFormat.R32Float          => Format.R32Float,
 | 
			
		||||
                TextureFormat.R32Uint           => Format.R32Uint,
 | 
			
		||||
                TextureFormat.R32Sint           => Format.R32Sint,
 | 
			
		||||
                TextureFormat.R8G8Unorm         => Format.R8G8Unorm,
 | 
			
		||||
                TextureFormat.R8G8Snorm         => Format.R8G8Snorm,
 | 
			
		||||
                TextureFormat.R8G8Uint          => Format.R8G8Uint,
 | 
			
		||||
                TextureFormat.R8G8Sint          => Format.R8G8Sint,
 | 
			
		||||
                TextureFormat.R16G16Float       => Format.R16G16Float,
 | 
			
		||||
                TextureFormat.R16G16Unorm       => Format.R16G16Unorm,
 | 
			
		||||
                TextureFormat.R16G16Snorm       => Format.R16G16Snorm,
 | 
			
		||||
                TextureFormat.R16G16Uint        => Format.R16G16Uint,
 | 
			
		||||
                TextureFormat.R16G16Sint        => Format.R16G16Sint,
 | 
			
		||||
                TextureFormat.R32G32Float       => Format.R32G32Float,
 | 
			
		||||
                TextureFormat.R32G32Uint        => Format.R32G32Uint,
 | 
			
		||||
                TextureFormat.R32G32Sint        => Format.R32G32Sint,
 | 
			
		||||
                TextureFormat.R8G8B8A8Unorm     => Format.R8G8B8A8Unorm,
 | 
			
		||||
                TextureFormat.R8G8B8A8Snorm     => Format.R8G8B8A8Snorm,
 | 
			
		||||
                TextureFormat.R8G8B8A8Uint      => Format.R8G8B8A8Uint,
 | 
			
		||||
                TextureFormat.R8G8B8A8Sint      => Format.R8G8B8A8Sint,
 | 
			
		||||
                TextureFormat.R16G16B16A16Float => Format.R16G16B16A16Float,
 | 
			
		||||
                TextureFormat.R16G16B16A16Unorm => Format.R16G16B16A16Unorm,
 | 
			
		||||
                TextureFormat.R16G16B16A16Snorm => Format.R16G16B16A16Snorm,
 | 
			
		||||
                TextureFormat.R16G16B16A16Uint  => Format.R16G16B16A16Uint,
 | 
			
		||||
                TextureFormat.R16G16B16A16Sint  => Format.R16G16B16A16Sint,
 | 
			
		||||
                TextureFormat.R32G32B32A32Float => Format.R32G32B32A32Float,
 | 
			
		||||
                TextureFormat.R32G32B32A32Uint  => Format.R32G32B32A32Uint,
 | 
			
		||||
                TextureFormat.R32G32B32A32Sint  => Format.R32G32B32A32Sint,
 | 
			
		||||
                TextureFormat.R10G10B10A2Unorm  => Format.R10G10B10A2Unorm,
 | 
			
		||||
                TextureFormat.R10G10B10A2Uint   => Format.R10G10B10A2Uint,
 | 
			
		||||
                TextureFormat.R11G11B10Float    => Format.R11G11B10Float,
 | 
			
		||||
                _                               => 0,
 | 
			
		||||
                TextureFormat.R8Unorm           => new(Format.R8Unorm, 1, 1, 1, 1),
 | 
			
		||||
                TextureFormat.R8Snorm           => new(Format.R8Snorm, 1, 1, 1, 1),
 | 
			
		||||
                TextureFormat.R8Uint            => new(Format.R8Uint, 1, 1, 1, 1),
 | 
			
		||||
                TextureFormat.R8Sint            => new(Format.R8Sint, 1, 1, 1, 1),
 | 
			
		||||
                TextureFormat.R16Float          => new(Format.R16Float, 1, 1, 2, 1),
 | 
			
		||||
                TextureFormat.R16Unorm          => new(Format.R16Unorm, 1, 1, 2, 1),
 | 
			
		||||
                TextureFormat.R16Snorm          => new(Format.R16Snorm, 1, 1, 2, 1),
 | 
			
		||||
                TextureFormat.R16Uint           => new(Format.R16Uint, 1, 1, 2, 1),
 | 
			
		||||
                TextureFormat.R16Sint           => new(Format.R16Sint, 1, 1, 2, 1),
 | 
			
		||||
                TextureFormat.R32Float          => new(Format.R32Float, 1, 1, 4, 1),
 | 
			
		||||
                TextureFormat.R32Uint           => new(Format.R32Uint, 1, 1, 4, 1),
 | 
			
		||||
                TextureFormat.R32Sint           => new(Format.R32Sint, 1, 1, 4, 1),
 | 
			
		||||
                TextureFormat.R8G8Unorm         => new(Format.R8G8Unorm, 1, 1, 2, 2),
 | 
			
		||||
                TextureFormat.R8G8Snorm         => new(Format.R8G8Snorm, 1, 1, 2, 2),
 | 
			
		||||
                TextureFormat.R8G8Uint          => new(Format.R8G8Uint, 1, 1, 2, 2),
 | 
			
		||||
                TextureFormat.R8G8Sint          => new(Format.R8G8Sint, 1, 1, 2, 2),
 | 
			
		||||
                TextureFormat.R16G16Float       => new(Format.R16G16Float, 1, 1, 4, 2),
 | 
			
		||||
                TextureFormat.R16G16Unorm       => new(Format.R16G16Unorm, 1, 1, 4, 2),
 | 
			
		||||
                TextureFormat.R16G16Snorm       => new(Format.R16G16Snorm, 1, 1, 4, 2),
 | 
			
		||||
                TextureFormat.R16G16Uint        => new(Format.R16G16Uint, 1, 1, 4, 2),
 | 
			
		||||
                TextureFormat.R16G16Sint        => new(Format.R16G16Sint, 1, 1, 4, 2),
 | 
			
		||||
                TextureFormat.R32G32Float       => new(Format.R32G32Float, 1, 1, 8, 2),
 | 
			
		||||
                TextureFormat.R32G32Uint        => new(Format.R32G32Uint, 1, 1, 8, 2),
 | 
			
		||||
                TextureFormat.R32G32Sint        => new(Format.R32G32Sint, 1, 1, 8, 2),
 | 
			
		||||
                TextureFormat.R8G8B8A8Unorm     => new(Format.R8G8B8A8Unorm, 1, 1, 4, 4),
 | 
			
		||||
                TextureFormat.R8G8B8A8Snorm     => new(Format.R8G8B8A8Snorm, 1, 1, 4, 4),
 | 
			
		||||
                TextureFormat.R8G8B8A8Uint      => new(Format.R8G8B8A8Uint, 1, 1, 4, 4),
 | 
			
		||||
                TextureFormat.R8G8B8A8Sint      => new(Format.R8G8B8A8Sint, 1, 1, 4, 4),
 | 
			
		||||
                TextureFormat.R16G16B16A16Float => new(Format.R16G16B16A16Float, 1, 1, 8, 4),
 | 
			
		||||
                TextureFormat.R16G16B16A16Unorm => new(Format.R16G16B16A16Unorm, 1, 1, 8, 4),
 | 
			
		||||
                TextureFormat.R16G16B16A16Snorm => new(Format.R16G16B16A16Snorm, 1, 1, 8, 4),
 | 
			
		||||
                TextureFormat.R16G16B16A16Uint  => new(Format.R16G16B16A16Uint, 1, 1, 8, 4),
 | 
			
		||||
                TextureFormat.R16G16B16A16Sint  => new(Format.R16G16B16A16Sint, 1, 1, 8, 4),
 | 
			
		||||
                TextureFormat.R32G32B32A32Float => new(Format.R32G32B32A32Float, 1, 1, 16, 4),
 | 
			
		||||
                TextureFormat.R32G32B32A32Uint  => new(Format.R32G32B32A32Uint, 1, 1, 16, 4),
 | 
			
		||||
                TextureFormat.R32G32B32A32Sint  => new(Format.R32G32B32A32Sint, 1, 1, 16, 4),
 | 
			
		||||
                TextureFormat.R10G10B10A2Unorm  => new(Format.R10G10B10A2Unorm, 1, 1, 4, 4),
 | 
			
		||||
                TextureFormat.R10G10B10A2Uint   => new(Format.R10G10B10A2Uint, 1, 1, 4, 4),
 | 
			
		||||
                TextureFormat.R11G11B10Float    => new(Format.R11G11B10Float, 1, 1, 4, 3),
 | 
			
		||||
                _                               => FormatInfo.Invalid,
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,11 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    readonly struct FormatInfo
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// An invalid texture format.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public static FormatInfo Invalid { get; } = new(0, 0, 0, 0, 0);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// A default, generic RGBA8 texture format.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -23,7 +28,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// <remarks>
 | 
			
		||||
        /// Must be 1 for non-compressed formats.
 | 
			
		||||
        /// </remarks>
 | 
			
		||||
        public int BlockWidth { get; }
 | 
			
		||||
        public byte BlockWidth { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The block height for compressed formats.
 | 
			
		||||
@@ -31,17 +36,17 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// <remarks>
 | 
			
		||||
        /// Must be 1 for non-compressed formats.
 | 
			
		||||
        /// </remarks>
 | 
			
		||||
        public int BlockHeight { get; }
 | 
			
		||||
        public byte BlockHeight { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The number of bytes occupied by a single pixel in memory of the texture data.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int BytesPerPixel { get; }
 | 
			
		||||
        public byte BytesPerPixel { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The maximum number of components this format has defined (in RGBA order).
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int Components { get; }
 | 
			
		||||
        public byte Components { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Whenever or not the texture format is a compressed format. Determined from block size.
 | 
			
		||||
@@ -57,10 +62,10 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// <param name="bytesPerPixel">The number of bytes occupied by a single pixel in memory of the texture data</param>
 | 
			
		||||
        public FormatInfo(
 | 
			
		||||
            Format format,
 | 
			
		||||
            int blockWidth,
 | 
			
		||||
            int blockHeight,
 | 
			
		||||
            int bytesPerPixel,
 | 
			
		||||
            int components)
 | 
			
		||||
            byte blockWidth,
 | 
			
		||||
            byte blockHeight,
 | 
			
		||||
            byte bytesPerPixel,
 | 
			
		||||
            byte components)
 | 
			
		||||
        {
 | 
			
		||||
            Format = format;
 | 
			
		||||
            BlockWidth = blockWidth;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// For images, indicates the format specified on the shader.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public Format Format { get; }
 | 
			
		||||
        public FormatInfo FormatInfo { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Shader texture host set index.
 | 
			
		||||
@@ -58,17 +58,17 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// Constructs the texture binding information structure.
 | 
			
		||||
        /// </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="formatInfo">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 set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
 | 
			
		||||
        public TextureBindingInfo(Target target, FormatInfo formatInfo, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
 | 
			
		||||
        {
 | 
			
		||||
            Target = target;
 | 
			
		||||
            Format = format;
 | 
			
		||||
            FormatInfo = formatInfo;
 | 
			
		||||
            Set = set;
 | 
			
		||||
            Binding = binding;
 | 
			
		||||
            ArrayLength = arrayLength;
 | 
			
		||||
@@ -96,7 +96,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
            int cbufSlot,
 | 
			
		||||
            int handle,
 | 
			
		||||
            TextureUsageFlags flags,
 | 
			
		||||
            bool isSamplerOnly) : this(target, 0, set, binding, arrayLength, cbufSlot, handle, flags)
 | 
			
		||||
            bool isSamplerOnly) : this(target, FormatInfo.Invalid, set, binding, arrayLength, cbufSlot, handle, flags)
 | 
			
		||||
        {
 | 
			
		||||
            IsSamplerOnly = isSamplerOnly;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -659,7 +659,6 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
            int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1;
 | 
			
		||||
            length = Math.Min(length, bindingInfo.ArrayLength);
 | 
			
		||||
 | 
			
		||||
            Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
 | 
			
		||||
            ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
 | 
			
		||||
            ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
 | 
			
		||||
 | 
			
		||||
@@ -674,7 +673,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, out texture);
 | 
			
		||||
                    ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, bindingInfo.FormatInfo, out texture);
 | 
			
		||||
 | 
			
		||||
                    if (texture != null)
 | 
			
		||||
                    {
 | 
			
		||||
@@ -697,8 +696,6 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
 | 
			
		||||
                ISampler hostSampler = sampler?.GetHostSampler(texture);
 | 
			
		||||
 | 
			
		||||
                Format format = bindingInfo.Format;
 | 
			
		||||
 | 
			
		||||
                if (hostTexture != null && texture.Target == Target.TextureBuffer)
 | 
			
		||||
                {
 | 
			
		||||
                    // Ensure that the buffer texture is using the correct buffer as storage.
 | 
			
		||||
@@ -706,26 +703,15 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                    // to ensure we're not using a old buffer that was already deleted.
 | 
			
		||||
                    if (isImage)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (format == 0 && texture != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            format = texture.Format;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
 | 
			
		||||
                        _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format);
 | 
			
		||||
                        _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else if (isImage)
 | 
			
		||||
                {
 | 
			
		||||
                    if (format == 0 && texture != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        format = texture.Format;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    formats[index] = format;
 | 
			
		||||
                    textures[index] = hostTexture;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
@@ -737,7 +723,6 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
 | 
			
		||||
            if (isImage)
 | 
			
		||||
            {
 | 
			
		||||
                entry.ImageArray.SetFormats(0, formats);
 | 
			
		||||
                entry.ImageArray.SetImages(0, textures);
 | 
			
		||||
 | 
			
		||||
                SetImageArray(stage, bindingInfo, entry.ImageArray);
 | 
			
		||||
@@ -863,7 +848,6 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
 | 
			
		||||
            entry.UpdateData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer);
 | 
			
		||||
 | 
			
		||||
            Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
 | 
			
		||||
            ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
 | 
			
		||||
            ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
 | 
			
		||||
 | 
			
		||||
@@ -883,7 +867,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                    samplerId = TextureHandle.UnpackSamplerId(packedId);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture);
 | 
			
		||||
                ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture);
 | 
			
		||||
 | 
			
		||||
                if (texture != null)
 | 
			
		||||
                {
 | 
			
		||||
@@ -916,8 +900,6 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                    hostSampler = sampler?.GetHostSampler(texture);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Format format = bindingInfo.Format;
 | 
			
		||||
 | 
			
		||||
                if (hostTexture != null && texture.Target == Target.TextureBuffer)
 | 
			
		||||
                {
 | 
			
		||||
                    // Ensure that the buffer texture is using the correct buffer as storage.
 | 
			
		||||
@@ -925,26 +907,15 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                    // to ensure we're not using a old buffer that was already deleted.
 | 
			
		||||
                    if (isImage)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (format == 0 && texture != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            format = texture.Format;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
 | 
			
		||||
                        _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format);
 | 
			
		||||
                        _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else if (isImage)
 | 
			
		||||
                {
 | 
			
		||||
                    if (format == 0 && texture != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        format = texture.Format;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    formats[index] = format;
 | 
			
		||||
                    textures[index] = hostTexture;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
@@ -956,7 +927,6 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
 | 
			
		||||
            if (isImage)
 | 
			
		||||
            {
 | 
			
		||||
                entry.ImageArray.SetFormats(0, formats);
 | 
			
		||||
                entry.ImageArray.SetImages(0, textures);
 | 
			
		||||
 | 
			
		||||
                SetImageArray(stage, bindingInfo, entry.ImageArray);
 | 
			
		||||
 
 | 
			
		||||
@@ -522,7 +522,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                    // Ensure that the buffer texture is using the correct buffer as storage.
 | 
			
		||||
                    // Buffers are frequently re-created to accommodate larger data, so we need to re-bind
 | 
			
		||||
                    // to ensure we're not using a old buffer that was already deleted.
 | 
			
		||||
                    _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, bindingInfo.Format, false);
 | 
			
		||||
                    _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, false);
 | 
			
		||||
 | 
			
		||||
                    // Cache is not used for buffer texture, it must always rebind.
 | 
			
		||||
                    state.CachedTexture = null;
 | 
			
		||||
@@ -616,6 +616,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
 | 
			
		||||
                if (!poolModified &&
 | 
			
		||||
                    state.TextureHandle == textureId &&
 | 
			
		||||
                    state.ImageFormat == bindingInfo.FormatInfo.Format &&
 | 
			
		||||
                    state.CachedTexture != null &&
 | 
			
		||||
                    state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence)
 | 
			
		||||
                {
 | 
			
		||||
@@ -629,26 +630,22 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                        cachedTexture.SignalModified();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
 | 
			
		||||
 | 
			
		||||
                    if (state.ImageFormat != format ||
 | 
			
		||||
                        ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
 | 
			
		||||
                        UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)))
 | 
			
		||||
                    if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 && UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))
 | 
			
		||||
                    {
 | 
			
		||||
                        ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
 | 
			
		||||
 | 
			
		||||
                        state.Texture = hostTextureRebind;
 | 
			
		||||
                        state.ImageFormat = format;
 | 
			
		||||
 | 
			
		||||
                        _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind, format);
 | 
			
		||||
                        _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                state.TextureHandle = textureId;
 | 
			
		||||
                state.ImageFormat = bindingInfo.FormatInfo.Format;
 | 
			
		||||
 | 
			
		||||
                ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, out Texture texture);
 | 
			
		||||
                ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture);
 | 
			
		||||
 | 
			
		||||
                specStateMatches &= specState.MatchesImage(stage, index, descriptor);
 | 
			
		||||
 | 
			
		||||
@@ -660,14 +657,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                    // Buffers are frequently re-created to accommodate larger data, so we need to re-bind
 | 
			
		||||
                    // to ensure we're not using a old buffer that was already deleted.
 | 
			
		||||
 | 
			
		||||
                    Format format = bindingInfo.Format;
 | 
			
		||||
 | 
			
		||||
                    if (format == 0 && texture != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        format = texture.Format;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, format, true);
 | 
			
		||||
                    _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, true);
 | 
			
		||||
 | 
			
		||||
                    // Cache is not used for buffer texture, it must always rebind.
 | 
			
		||||
                    state.CachedTexture = null;
 | 
			
		||||
@@ -689,16 +679,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                    {
 | 
			
		||||
                        state.Texture = hostTexture;
 | 
			
		||||
 | 
			
		||||
                        Format format = bindingInfo.Format;
 | 
			
		||||
 | 
			
		||||
                        if (format == 0 && texture != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            format = texture.Format;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        state.ImageFormat = format;
 | 
			
		||||
 | 
			
		||||
                        _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture, format);
 | 
			
		||||
                        _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    state.CachedTexture = texture;
 | 
			
		||||
 
 | 
			
		||||
@@ -739,7 +739,8 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) ||
 | 
			
		||||
                   (lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm);
 | 
			
		||||
                   (lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm) ||
 | 
			
		||||
                   (lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R32Uint);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -75,6 +75,76 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        private readonly ConcurrentQueue<DereferenceRequest> _dereferenceQueue = new();
 | 
			
		||||
        private TextureDescriptor _defaultDescriptor;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// List of textures that shares the same memory region, but have different formats.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private class TextureAliasList
 | 
			
		||||
        {
 | 
			
		||||
            /// <summary>
 | 
			
		||||
            /// Alias texture.
 | 
			
		||||
            /// </summary>
 | 
			
		||||
            /// <param name="Format">Texture format</param>
 | 
			
		||||
            /// <param name="Texture">Texture</param>
 | 
			
		||||
            private readonly record struct Alias(Format Format, Texture Texture);
 | 
			
		||||
 | 
			
		||||
            /// <summary>
 | 
			
		||||
            /// List of texture aliases.
 | 
			
		||||
            /// </summary>
 | 
			
		||||
            private readonly List<Alias> _aliases;
 | 
			
		||||
 | 
			
		||||
            /// <summary>
 | 
			
		||||
            /// Creates a new instance of the texture alias list.
 | 
			
		||||
            /// </summary>
 | 
			
		||||
            public TextureAliasList()
 | 
			
		||||
            {
 | 
			
		||||
                _aliases = new List<Alias>();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /// <summary>
 | 
			
		||||
            /// Adds a new texture alias.
 | 
			
		||||
            /// </summary>
 | 
			
		||||
            /// <param name="format">Alias format</param>
 | 
			
		||||
            /// <param name="texture">Alias texture</param>
 | 
			
		||||
            public void Add(Format format, Texture texture)
 | 
			
		||||
            {
 | 
			
		||||
                _aliases.Add(new Alias(format, texture));
 | 
			
		||||
                texture.IncrementReferenceCount();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /// <summary>
 | 
			
		||||
            /// Finds a texture with the requested format, or returns null if not found.
 | 
			
		||||
            /// </summary>
 | 
			
		||||
            /// <param name="format">Format to find</param>
 | 
			
		||||
            /// <returns>Texture with the requested format, or null if not found</returns>
 | 
			
		||||
            public Texture Find(Format format)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var alias in _aliases)
 | 
			
		||||
                {
 | 
			
		||||
                    if (alias.Format == format)
 | 
			
		||||
                    {
 | 
			
		||||
                        return alias.Texture;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /// <summary>
 | 
			
		||||
            /// Removes all alias textures.
 | 
			
		||||
            /// </summary>
 | 
			
		||||
            public void Destroy()
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var entry in _aliases)
 | 
			
		||||
                {
 | 
			
		||||
                    entry.Texture.DecrementReferenceCount();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                _aliases.Clear();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private readonly Dictionary<Texture, TextureAliasList> _aliasLists;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Linked list node used on the texture pool cache.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -95,6 +165,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
 | 
			
		||||
        {
 | 
			
		||||
            _channel = channel;
 | 
			
		||||
            _aliasLists = new Dictionary<Texture, TextureAliasList>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@@ -115,14 +186,13 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
 | 
			
		||||
                if (texture == null)
 | 
			
		||||
                {
 | 
			
		||||
                    TextureInfo info = GetInfo(descriptor, out int layerSize);
 | 
			
		||||
 | 
			
		||||
                    // The dereference queue can put our texture back on the cache.
 | 
			
		||||
                    if ((texture = ProcessDereferenceQueue(id)) != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        return ref descriptor;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    TextureInfo info = GetInfo(descriptor, out int layerSize);
 | 
			
		||||
                    texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
 | 
			
		||||
 | 
			
		||||
                    // If this happens, then the texture address is invalid, we can't add it to the cache.
 | 
			
		||||
@@ -197,6 +267,51 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
            return ref GetInternal(id, out texture);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the texture descriptor and texture with the given ID.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <remarks>
 | 
			
		||||
        /// This method assumes that the pool has been manually synchronized before doing binding.
 | 
			
		||||
        /// </remarks>
 | 
			
		||||
        /// <param name="id">ID of the texture. This is effectively a zero-based index</param>
 | 
			
		||||
        /// <param name="formatInfo">Texture format information</param>
 | 
			
		||||
        /// <param name="texture">The texture with the given ID</param>
 | 
			
		||||
        /// <returns>The texture descriptor with the given ID</returns>
 | 
			
		||||
        public ref readonly TextureDescriptor GetForBinding(int id, FormatInfo formatInfo, out Texture texture)
 | 
			
		||||
        {
 | 
			
		||||
            if ((uint)id >= Items.Length)
 | 
			
		||||
            {
 | 
			
		||||
                texture = null;
 | 
			
		||||
                return ref _defaultDescriptor;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ref readonly TextureDescriptor descriptor = ref GetInternal(id, out texture);
 | 
			
		||||
 | 
			
		||||
            if (texture != null && formatInfo.Format != 0 && texture.Format != formatInfo.Format)
 | 
			
		||||
            {
 | 
			
		||||
                if (!_aliasLists.TryGetValue(texture, out TextureAliasList aliasList))
 | 
			
		||||
                {
 | 
			
		||||
                    _aliasLists.Add(texture, aliasList = new TextureAliasList());
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                texture = aliasList.Find(formatInfo.Format);
 | 
			
		||||
 | 
			
		||||
                if (texture == null)
 | 
			
		||||
                {
 | 
			
		||||
                    TextureInfo info = GetInfo(descriptor, out int layerSize);
 | 
			
		||||
                    info = ChangeFormat(info, formatInfo);
 | 
			
		||||
                    texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
 | 
			
		||||
 | 
			
		||||
                    if (texture != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        aliasList.Add(formatInfo.Format, texture);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ref descriptor;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Checks if the pool was modified, and returns the last sequence number where a modification was detected.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -234,6 +349,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                texture.DecrementReferenceCount();
 | 
			
		||||
                RemoveAliasList(texture);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -327,6 +443,8 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                {
 | 
			
		||||
                    texture.DecrementReferenceCount();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                RemoveAliasList(texture);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
@@ -369,6 +487,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                    if (Interlocked.Exchange(ref Items[id], null) != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        texture.DecrementReferenceCount(this, id);
 | 
			
		||||
                        RemoveAliasList(texture);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -622,6 +741,57 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
                   component == SwizzleComponent.Green;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Changes the format on the texture information structure, and also adjusts the width for the new format if needed.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="info">Texture information</param>
 | 
			
		||||
        /// <param name="dstFormat">New format</param>
 | 
			
		||||
        /// <returns>Texture information with the new format</returns>
 | 
			
		||||
        private static TextureInfo ChangeFormat(in TextureInfo info, FormatInfo dstFormat)
 | 
			
		||||
        {
 | 
			
		||||
            int width = info.Width;
 | 
			
		||||
 | 
			
		||||
            if (info.FormatInfo.BytesPerPixel != dstFormat.BytesPerPixel)
 | 
			
		||||
            {
 | 
			
		||||
                int stride = width * info.FormatInfo.BytesPerPixel;
 | 
			
		||||
                width = stride / dstFormat.BytesPerPixel;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new TextureInfo(
 | 
			
		||||
                info.GpuAddress,
 | 
			
		||||
                width,
 | 
			
		||||
                info.Height,
 | 
			
		||||
                info.DepthOrLayers,
 | 
			
		||||
                info.Levels,
 | 
			
		||||
                info.SamplesInX,
 | 
			
		||||
                info.SamplesInY,
 | 
			
		||||
                info.Stride,
 | 
			
		||||
                info.IsLinear,
 | 
			
		||||
                info.GobBlocksInY,
 | 
			
		||||
                info.GobBlocksInZ,
 | 
			
		||||
                info.GobBlocksInTileX,
 | 
			
		||||
                info.Target,
 | 
			
		||||
                dstFormat,
 | 
			
		||||
                info.DepthStencilMode,
 | 
			
		||||
                info.SwizzleR,
 | 
			
		||||
                info.SwizzleG,
 | 
			
		||||
                info.SwizzleB,
 | 
			
		||||
                info.SwizzleA);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Removes all aliases for a texture.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="texture">Texture to have the aliases removed</param>
 | 
			
		||||
        private void RemoveAliasList(Texture texture)
 | 
			
		||||
        {
 | 
			
		||||
            if (_aliasLists.TryGetValue(texture, out TextureAliasList aliasList))
 | 
			
		||||
            {
 | 
			
		||||
                _aliasLists.Remove(texture);
 | 
			
		||||
                aliasList.Destroy();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Decrements the reference count of the texture.
 | 
			
		||||
        /// This indicates that the texture pool is not using it anymore.
 | 
			
		||||
@@ -629,7 +799,11 @@ namespace Ryujinx.Graphics.Gpu.Image
 | 
			
		||||
        /// <param name="item">The texture to be deleted</param>
 | 
			
		||||
        protected override void Delete(Texture item)
 | 
			
		||||
        {
 | 
			
		||||
            item?.DecrementReferenceCount(this);
 | 
			
		||||
            if (item != null)
 | 
			
		||||
            {
 | 
			
		||||
                item.DecrementReferenceCount(this);
 | 
			
		||||
                RemoveAliasList(item);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void Dispose()
 | 
			
		||||
 
 | 
			
		||||
@@ -509,7 +509,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
 | 
			
		||||
 | 
			
		||||
                    if (binding.IsImage)
 | 
			
		||||
                    {
 | 
			
		||||
                        _context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture, binding.Format);
 | 
			
		||||
                        _context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
@@ -873,12 +873,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
 | 
			
		||||
            ITexture texture,
 | 
			
		||||
            MultiRange range,
 | 
			
		||||
            TextureBindingInfo bindingInfo,
 | 
			
		||||
            Format format,
 | 
			
		||||
            bool isImage)
 | 
			
		||||
        {
 | 
			
		||||
            _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
 | 
			
		||||
 | 
			
		||||
            _bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, format, isImage));
 | 
			
		||||
            _bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, isImage));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@@ -897,12 +896,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
 | 
			
		||||
            ITexture texture,
 | 
			
		||||
            MultiRange range,
 | 
			
		||||
            TextureBindingInfo bindingInfo,
 | 
			
		||||
            int index,
 | 
			
		||||
            Format format)
 | 
			
		||||
            int index)
 | 
			
		||||
        {
 | 
			
		||||
            _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
 | 
			
		||||
 | 
			
		||||
            _bufferTextureArrays.Add(new BufferTextureArrayBinding<ITextureArray>(array, texture, range, bindingInfo, index, format));
 | 
			
		||||
            _bufferTextureArrays.Add(new BufferTextureArrayBinding<ITextureArray>(array, texture, range, bindingInfo, index));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@@ -921,12 +919,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
 | 
			
		||||
            ITexture texture,
 | 
			
		||||
            MultiRange range,
 | 
			
		||||
            TextureBindingInfo bindingInfo,
 | 
			
		||||
            int index,
 | 
			
		||||
            Format format)
 | 
			
		||||
            int index)
 | 
			
		||||
        {
 | 
			
		||||
            _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
 | 
			
		||||
 | 
			
		||||
            _bufferImageArrays.Add(new BufferTextureArrayBinding<IImageArray>(array, texture, range, bindingInfo, index, format));
 | 
			
		||||
            _bufferImageArrays.Add(new BufferTextureArrayBinding<IImageArray>(array, texture, range, bindingInfo, index));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -34,33 +34,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int Index { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The image format for the binding.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public Format Format { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Create a new buffer texture binding.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="array">Array</param>
 | 
			
		||||
        /// <param name="texture">Buffer texture</param>
 | 
			
		||||
        /// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
 | 
			
		||||
        /// <param name="bindingInfo">Binding info</param>
 | 
			
		||||
        /// <param name="index">Index of the binding on the array</param>
 | 
			
		||||
        /// <param name="format">Binding format</param>
 | 
			
		||||
        public BufferTextureArrayBinding(
 | 
			
		||||
            T array,
 | 
			
		||||
            ITexture texture,
 | 
			
		||||
            MultiRange range,
 | 
			
		||||
            TextureBindingInfo bindingInfo,
 | 
			
		||||
            int index,
 | 
			
		||||
            Format format)
 | 
			
		||||
            int index)
 | 
			
		||||
        {
 | 
			
		||||
            Array = array;
 | 
			
		||||
            Texture = texture;
 | 
			
		||||
            Range = range;
 | 
			
		||||
            BindingInfo = bindingInfo;
 | 
			
		||||
            Index = index;
 | 
			
		||||
            Format = format;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,11 +30,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public TextureBindingInfo BindingInfo { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The image format for the binding.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public Format Format { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Whether the binding is for an image or a sampler.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -47,21 +42,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
 | 
			
		||||
        /// <param name="texture">Buffer texture</param>
 | 
			
		||||
        /// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
 | 
			
		||||
        /// <param name="bindingInfo">Binding info</param>
 | 
			
		||||
        /// <param name="format">Binding format</param>
 | 
			
		||||
        /// <param name="isImage">Whether the binding is for an image or a sampler</param>
 | 
			
		||||
        public BufferTextureBinding(
 | 
			
		||||
            ShaderStage stage,
 | 
			
		||||
            ITexture texture,
 | 
			
		||||
            MultiRange range,
 | 
			
		||||
            TextureBindingInfo bindingInfo,
 | 
			
		||||
            Format format,
 | 
			
		||||
            bool isImage)
 | 
			
		||||
        {
 | 
			
		||||
            Stage = stage;
 | 
			
		||||
            Texture = texture;
 | 
			
		||||
            Range = range;
 | 
			
		||||
            BindingInfo = bindingInfo;
 | 
			
		||||
            Format = format;
 | 
			
		||||
            IsImage = isImage;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -86,11 +86,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
 | 
			
		||||
                ImageBindings[i] = stage.Info.Images.Select(descriptor =>
 | 
			
		||||
                {
 | 
			
		||||
                    Target target = ShaderTexture.GetTarget(descriptor.Type);
 | 
			
		||||
                    Format format = ShaderTexture.GetFormat(descriptor.Format);
 | 
			
		||||
                    FormatInfo formatInfo = ShaderTexture.GetFormatInfo(descriptor.Format);
 | 
			
		||||
 | 
			
		||||
                    var result = new TextureBindingInfo(
 | 
			
		||||
                        target,
 | 
			
		||||
                        format,
 | 
			
		||||
                        formatInfo,
 | 
			
		||||
                        descriptor.Set,
 | 
			
		||||
                        descriptor.Binding,
 | 
			
		||||
                        descriptor.ArrayLength,
 | 
			
		||||
 
 | 
			
		||||
@@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu
 | 
			
		||||
            bool isLinear,
 | 
			
		||||
            int gobBlocksInY,
 | 
			
		||||
            Format format,
 | 
			
		||||
            int bytesPerPixel,
 | 
			
		||||
            byte bytesPerPixel,
 | 
			
		||||
            ImageCrop crop,
 | 
			
		||||
            Action<GpuContext, object> acquireCallback,
 | 
			
		||||
            Action<object> releaseCallback,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
using OpenTK.Graphics.OpenGL;
 | 
			
		||||
using Ryujinx.Graphics.GAL;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Graphics.OpenGL.Image
 | 
			
		||||
{
 | 
			
		||||
@@ -19,14 +18,6 @@ namespace Ryujinx.Graphics.OpenGL.Image
 | 
			
		||||
            _images = new TextureRef[size];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetFormats(int index, GAL.Format[] imageFormats)
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < imageFormats.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                _images[index + i].Format = imageFormats[i];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImages(int index, ITexture[] images)
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < images.Length; i++)
 | 
			
		||||
@@ -36,6 +27,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
 | 
			
		||||
                if (image is TextureBase imageBase)
 | 
			
		||||
                {
 | 
			
		||||
                    _images[index + i].Handle = imageBase.Handle;
 | 
			
		||||
                    _images[index + i].Format = imageBase.Format;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.OpenGL
 | 
			
		||||
 | 
			
		||||
        private readonly Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount];
 | 
			
		||||
 | 
			
		||||
        private readonly (TextureBase, Format)[] _images;
 | 
			
		||||
        private readonly TextureBase[] _images;
 | 
			
		||||
        private TextureBase _unit0Texture;
 | 
			
		||||
        private Sampler _unit0Sampler;
 | 
			
		||||
 | 
			
		||||
@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL
 | 
			
		||||
            _fragmentOutputMap = uint.MaxValue;
 | 
			
		||||
            _componentMasks = uint.MaxValue;
 | 
			
		||||
 | 
			
		||||
            _images = new (TextureBase, Format)[SavedImages];
 | 
			
		||||
            _images = new TextureBase[SavedImages];
 | 
			
		||||
 | 
			
		||||
            _tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers];
 | 
			
		||||
            _tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers];
 | 
			
		||||
@@ -935,11 +935,11 @@ namespace Ryujinx.Graphics.OpenGL
 | 
			
		||||
            SetFrontFace(_frontFace = frontFace.Convert());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat)
 | 
			
		||||
        public void SetImage(ShaderStage stage, int binding, ITexture texture)
 | 
			
		||||
        {
 | 
			
		||||
            if ((uint)binding < SavedImages)
 | 
			
		||||
            {
 | 
			
		||||
                _images[binding] = (texture as TextureBase, imageFormat);
 | 
			
		||||
                _images[binding] = texture as TextureBase;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (texture == null)
 | 
			
		||||
@@ -950,7 +950,7 @@ namespace Ryujinx.Graphics.OpenGL
 | 
			
		||||
 | 
			
		||||
            TextureBase texBase = (TextureBase)texture;
 | 
			
		||||
 | 
			
		||||
            SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
 | 
			
		||||
            SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
 | 
			
		||||
 | 
			
		||||
            if (format != 0)
 | 
			
		||||
            {
 | 
			
		||||
@@ -1622,11 +1622,11 @@ namespace Ryujinx.Graphics.OpenGL
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < SavedImages; i++)
 | 
			
		||||
            {
 | 
			
		||||
                (TextureBase texBase, Format imageFormat) = _images[i];
 | 
			
		||||
                TextureBase texBase = _images[i];
 | 
			
		||||
 | 
			
		||||
                if (texBase != null)
 | 
			
		||||
                {
 | 
			
		||||
                    SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
 | 
			
		||||
                    SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
 | 
			
		||||
 | 
			
		||||
                    if (format != 0)
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,6 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        private readonly ImageRef[] _imageRefs;
 | 
			
		||||
        private readonly TextureBuffer[] _bufferTextureRefs;
 | 
			
		||||
        private readonly TextureBuffer[] _bufferImageRefs;
 | 
			
		||||
        private readonly Format[] _bufferImageFormats;
 | 
			
		||||
 | 
			
		||||
        private ArrayRef<TextureArray>[] _textureArrayRefs;
 | 
			
		||||
        private ArrayRef<ImageArray>[] _imageArrayRefs;
 | 
			
		||||
@@ -141,7 +140,6 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            _imageRefs = new ImageRef[Constants.MaxImageBindings * 2];
 | 
			
		||||
            _bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2];
 | 
			
		||||
            _bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2];
 | 
			
		||||
            _bufferImageFormats = new Format[Constants.MaxImageBindings * 2];
 | 
			
		||||
 | 
			
		||||
            _textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
 | 
			
		||||
            _imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
 | 
			
		||||
@@ -391,17 +389,11 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            _dirty = DirtyFlags.All;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImage(
 | 
			
		||||
            CommandBufferScoped cbs,
 | 
			
		||||
            ShaderStage stage,
 | 
			
		||||
            int binding,
 | 
			
		||||
            ITexture image,
 | 
			
		||||
            Format imageFormat)
 | 
			
		||||
        public void SetImage(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture image)
 | 
			
		||||
        {
 | 
			
		||||
            if (image is TextureBuffer imageBuffer)
 | 
			
		||||
            {
 | 
			
		||||
                _bufferImageRefs[binding] = imageBuffer;
 | 
			
		||||
                _bufferImageFormats[binding] = imageFormat;
 | 
			
		||||
            }
 | 
			
		||||
            else if (image is TextureView view)
 | 
			
		||||
            {
 | 
			
		||||
@@ -410,13 +402,12 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
                iRef.View?.ClearUsage(FeedbackLoopHazards);
 | 
			
		||||
                view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
 | 
			
		||||
 | 
			
		||||
                iRef = new(stage, view, view.GetView(imageFormat).GetIdentityImageView());
 | 
			
		||||
                iRef = new(stage, view, view.GetIdentityImageView());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _imageRefs[binding] = default;
 | 
			
		||||
                _bufferImageRefs[binding] = null;
 | 
			
		||||
                _bufferImageFormats[binding] = default;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SignalDirty(DirtyFlags.Image);
 | 
			
		||||
@@ -923,7 +914,7 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
 | 
			
		||||
                            for (int i = 0; i < count; i++)
 | 
			
		||||
                            {
 | 
			
		||||
                                bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, _bufferImageFormats[binding + i], true) ?? default;
 | 
			
		||||
                                bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, true) ?? default;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            tu.Push<BufferView>(bufferImages[..count]);
 | 
			
		||||
 
 | 
			
		||||
@@ -154,7 +154,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
 | 
			
		||||
            int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
 | 
			
		||||
 | 
			
		||||
            _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
 | 
			
		||||
            _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
 | 
			
		||||
            _pipeline.ComputeBarrier();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -75,7 +75,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
 | 
			
		||||
            var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
 | 
			
		||||
            var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
 | 
			
		||||
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _texture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
 | 
			
		||||
            _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
 | 
			
		||||
 | 
			
		||||
            _pipeline.ComputeBarrier();
 | 
			
		||||
 
 | 
			
		||||
@@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
 | 
			
		||||
 | 
			
		||||
            buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
 | 
			
		||||
            _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
 | 
			
		||||
            _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
 | 
			
		||||
            _pipeline.ComputeBarrier();
 | 
			
		||||
 | 
			
		||||
@@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
 | 
			
		||||
            _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear);
 | 
			
		||||
            _pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear);
 | 
			
		||||
            _pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear);
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
 | 
			
		||||
            _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
 | 
			
		||||
            _pipeline.ComputeBarrier();
 | 
			
		||||
 | 
			
		||||
@@ -238,7 +238,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
 | 
			
		||||
            _pipeline.Specialize(_specConstants);
 | 
			
		||||
            _pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear);
 | 
			
		||||
            _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear);
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
 | 
			
		||||
            _pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
 | 
			
		||||
            _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
 | 
			
		||||
            _pipeline.ComputeBarrier();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1039,7 +1039,7 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
                    var dstView = Create2DLayerView(dst, dstLayer + z, dstLevel + l);
 | 
			
		||||
 | 
			
		||||
                    _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
 | 
			
		||||
                    _pipeline.SetImage(ShaderStage.Compute, 0, dstView, dstFormat);
 | 
			
		||||
                    _pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(dstFormat));
 | 
			
		||||
 | 
			
		||||
                    int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32;
 | 
			
		||||
                    int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32;
 | 
			
		||||
@@ -1168,7 +1168,7 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
                    var dstView = Create2DLayerView(dst, dstLayer + z, 0);
 | 
			
		||||
 | 
			
		||||
                    _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
 | 
			
		||||
                    _pipeline.SetImage(ShaderStage.Compute, 0, dstView, format);
 | 
			
		||||
                    _pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(format));
 | 
			
		||||
 | 
			
		||||
                    _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,6 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        {
 | 
			
		||||
            public TextureStorage Storage;
 | 
			
		||||
            public TextureView View;
 | 
			
		||||
            public GAL.Format ImageFormat;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private readonly TextureRef[] _textureRefs;
 | 
			
		||||
@@ -52,16 +51,6 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            _isBuffer = isBuffer;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetFormats(int index, GAL.Format[] imageFormats)
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < imageFormats.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                _textureRefs[index + i].ImageFormat = imageFormats[i];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SetDirty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImages(int index, ITexture[] images)
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < images.Length; i++)
 | 
			
		||||
@@ -142,7 +131,7 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
                ref var texture = ref textures[i];
 | 
			
		||||
                ref var refs = ref _textureRefs[i];
 | 
			
		||||
 | 
			
		||||
                if (i > 0 && _textureRefs[i - 1].View == refs.View && _textureRefs[i - 1].ImageFormat == refs.ImageFormat)
 | 
			
		||||
                if (i > 0 && _textureRefs[i - 1].View == refs.View)
 | 
			
		||||
                {
 | 
			
		||||
                    texture = textures[i - 1];
 | 
			
		||||
 | 
			
		||||
@@ -150,7 +139,7 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                texture.ImageLayout = ImageLayout.General;
 | 
			
		||||
                texture.ImageView = refs.View?.GetView(refs.ImageFormat).GetIdentityImageView().Get(cbs).Value ?? default;
 | 
			
		||||
                texture.ImageView = refs.View?.GetIdentityImageView().Get(cbs).Value ?? default;
 | 
			
		||||
 | 
			
		||||
                if (texture.ImageView.Handle == 0)
 | 
			
		||||
                {
 | 
			
		||||
@@ -167,7 +156,7 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < bufferTextures.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, _textureRefs[i].ImageFormat, true) ?? default;
 | 
			
		||||
                bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, true) ?? default;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return bufferTextures;
 | 
			
		||||
 
 | 
			
		||||
@@ -836,9 +836,9 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
            SignalStateChange();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImage(ShaderStage stage, int binding, ITexture image, Format imageFormat)
 | 
			
		||||
        public void SetImage(ShaderStage stage, int binding, ITexture image)
 | 
			
		||||
        {
 | 
			
		||||
            _descriptorSetUpdater.SetImage(Cbs, stage, binding, image, imageFormat);
 | 
			
		||||
            _descriptorSetUpdater.SetImage(Cbs, stage, binding, image);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetImage(int binding, Auto<DisposableImageView> image)
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
        private int _offset;
 | 
			
		||||
        private int _size;
 | 
			
		||||
        private Auto<DisposableBufferView> _bufferView;
 | 
			
		||||
        private Dictionary<Format, Auto<DisposableBufferView>> _selfManagedViews;
 | 
			
		||||
 | 
			
		||||
        private int _bufferCount;
 | 
			
		||||
 | 
			
		||||
@@ -80,16 +79,6 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
 | 
			
		||||
        private void ReleaseImpl()
 | 
			
		||||
        {
 | 
			
		||||
            if (_selfManagedViews != null)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var bufferView in _selfManagedViews.Values)
 | 
			
		||||
                {
 | 
			
		||||
                    bufferView.Dispose();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                _selfManagedViews = null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _bufferView?.Dispose();
 | 
			
		||||
            _bufferView = null;
 | 
			
		||||
        }
 | 
			
		||||
@@ -137,28 +126,5 @@ namespace Ryujinx.Graphics.Vulkan
 | 
			
		||||
 | 
			
		||||
            return _bufferView?.Get(cbs, _offset, _size, write).Value ?? default;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public BufferView GetBufferView(CommandBufferScoped cbs, Format format, bool write)
 | 
			
		||||
        {
 | 
			
		||||
            var vkFormat = FormatTable.GetFormat(format);
 | 
			
		||||
            if (vkFormat == VkFormat)
 | 
			
		||||
            {
 | 
			
		||||
                return GetBufferView(cbs, write);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (_selfManagedViews != null && _selfManagedViews.TryGetValue(format, out var bufferView))
 | 
			
		||||
            {
 | 
			
		||||
                return bufferView.Get(cbs, _offset, _size, write).Value;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bufferView = _gd.BufferManager.CreateView(_bufferHandle, vkFormat, _offset, _size, ReleaseImpl);
 | 
			
		||||
 | 
			
		||||
            if (bufferView != null)
 | 
			
		||||
            {
 | 
			
		||||
                (_selfManagedViews ??= new Dictionary<Format, Auto<DisposableBufferView>>()).Add(format, bufferView);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return bufferView?.Get(cbs, _offset, _size, write).Value ?? default;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -412,9 +412,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
 | 
			
		||||
 | 
			
		||||
            Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);
 | 
			
		||||
 | 
			
		||||
            int bytesPerPixel =
 | 
			
		||||
            byte bytesPerPixel =
 | 
			
		||||
                format == Format.B5G6R5Unorm ||
 | 
			
		||||
                format == Format.R4G4B4A4Unorm ? 2 : 4;
 | 
			
		||||
                format == Format.R4G4B4A4Unorm ? (byte)2 : (byte)4;
 | 
			
		||||
 | 
			
		||||
            int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user