From 02a5f75fab89e521adce22037a8fe1b875a4d5fc Mon Sep 17 00:00:00 2001 From: KeatonTheBot Date: Fri, 11 Oct 2024 14:36:39 -0500 Subject: [PATCH] Revert PRs 7226(1.1.1385), 7311(1.1.1392), and 7312 (1.1.1396). * "Vulkan: Feedback loop detection and barriers (#7226)" * "Change image format view handling to allow view incompatible formats (#7311)" * "Add support for sampler sRGB disable (#7312)" * These changes prevent slowdowns in several areas in Paper Mario: The Thousand Year Door, possibly other games. --- .../GraphicsDriver/DriverUtilities.cs | 24 +- src/Ryujinx.Common/Utilities/OsUtils.cs | 24 -- src/Ryujinx.Graphics.GAL/IImageArray.cs | 1 + src/Ryujinx.Graphics.GAL/IPipeline.cs | 2 +- .../Multithreading/CommandHelper.cs | 1 + .../Multithreading/CommandType.cs | 1 + .../ImageArray/ImageArraySetFormatsCommand.cs | 26 +++ .../Commands/SetImageCommand.cs | 6 +- .../Resources/ThreadedImageArray.cs | 6 + .../Multithreading/ThreadedPipeline.cs | 4 +- .../Engine/ShaderTexture.cs | 83 ++++--- src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs | 21 +- src/Ryujinx.Graphics.Gpu/Image/Sampler.cs | 7 - .../Image/SamplerDescriptor.cs | 9 - .../Image/TextureBindingInfo.cs | 10 +- .../Image/TextureBindingsArrayCache.cs | 42 +++- .../Image/TextureBindingsManager.cs | 45 ++-- .../Image/TextureCompatibility.cs | 3 +- src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 208 +----------------- .../Memory/BufferManager.cs | 15 +- .../Memory/BufferTextureArrayBinding.cs | 11 +- .../Memory/BufferTextureBinding.cs | 8 + .../Shader/CachedShaderBindings.cs | 4 +- src/Ryujinx.Graphics.Gpu/Window.cs | 2 +- .../Image/ImageArray.cs | 10 +- src/Ryujinx.Graphics.OpenGL/Pipeline.cs | 14 +- src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs | 39 ++-- .../DescriptorSetUpdater.cs | 77 +++---- .../Effects/FsrScalingFilter.cs | 2 +- .../Effects/FxaaPostProcessingEffect.cs | 2 +- .../Effects/SmaaPostProcessingEffect.cs | 6 +- .../FeedbackLoopAspects.cs | 12 - .../FramebufferParams.cs | 21 -- .../HardwareCapabilities.cs | 6 - src/Ryujinx.Graphics.Vulkan/HelperShader.cs | 4 +- src/Ryujinx.Graphics.Vulkan/ImageArray.cs | 17 +- src/Ryujinx.Graphics.Vulkan/PipelineBase.cs | 126 ++--------- .../PipelineDynamicState.cs | 34 +-- src/Ryujinx.Graphics.Vulkan/PipelineFull.cs | 4 +- src/Ryujinx.Graphics.Vulkan/PipelineState.cs | 38 +--- src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs | 34 +++ src/Ryujinx.Graphics.Vulkan/TextureStorage.cs | 74 +------ src/Ryujinx.Graphics.Vulkan/TextureView.cs | 32 +-- .../VulkanInitialization.cs | 54 ----- src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | 34 --- src/Ryujinx.Gtk3/Program.cs | 23 +- .../Services/SurfaceFlinger/SurfaceFlinger.cs | 4 +- src/Ryujinx.Headless.SDL2/Program.cs | 3 - src/Ryujinx/Program.cs | 4 +- 49 files changed, 358 insertions(+), 879 deletions(-) delete mode 100644 src/Ryujinx.Common/Utilities/OsUtils.cs create mode 100644 src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArraySetFormatsCommand.cs delete mode 100644 src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs diff --git a/src/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs b/src/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs index a9163f348..7fe2a4f02 100644 --- a/src/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs +++ b/src/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs @@ -1,33 +1,13 @@ -using Ryujinx.Common.Utilities; using System; namespace Ryujinx.Common.GraphicsDriver { public static class DriverUtilities { - private static void AddMesaFlags(string envVar, string newFlags) - { - string existingFlags = Environment.GetEnvironmentVariable(envVar); - - string flags = existingFlags == null ? newFlags : $"{existingFlags},{newFlags}"; - - OsUtils.SetEnvironmentVariableNoCaching(envVar, flags); - } - - public static void InitDriverConfig(bool oglThreading) - { - if (OperatingSystem.IsLinux()) - { - AddMesaFlags("RADV_DEBUG", "nodcc"); - } - - ToggleOGLThreading(oglThreading); - } - public static void ToggleOGLThreading(bool enabled) { - OsUtils.SetEnvironmentVariableNoCaching("mesa_glthread", enabled.ToString().ToLower()); - OsUtils.SetEnvironmentVariableNoCaching("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0"); + Environment.SetEnvironmentVariable("mesa_glthread", enabled.ToString().ToLower()); + Environment.SetEnvironmentVariable("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0"); try { diff --git a/src/Ryujinx.Common/Utilities/OsUtils.cs b/src/Ryujinx.Common/Utilities/OsUtils.cs deleted file mode 100644 index a0791b092..000000000 --- a/src/Ryujinx.Common/Utilities/OsUtils.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Common.Utilities -{ - public partial class OsUtils - { - [LibraryImport("libc", SetLastError = true)] - private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite); - - public static void SetEnvironmentVariableNoCaching(string key, string value) - { - // Set the value in the cached environment variables, too. - Environment.SetEnvironmentVariable(key, value); - - if (!OperatingSystem.IsWindows()) - { - int res = setenv(key, value, 1); - Debug.Assert(res != -1); - } - } - } -} diff --git a/src/Ryujinx.Graphics.GAL/IImageArray.cs b/src/Ryujinx.Graphics.GAL/IImageArray.cs index d87314eb8..d119aa9fb 100644 --- a/src/Ryujinx.Graphics.GAL/IImageArray.cs +++ b/src/Ryujinx.Graphics.GAL/IImageArray.cs @@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.GAL { public interface IImageArray : IDisposable { + void SetFormats(int index, Format[] imageFormats); void SetImages(int index, ITexture[] images); } } diff --git a/src/Ryujinx.Graphics.GAL/IPipeline.cs b/src/Ryujinx.Graphics.GAL/IPipeline.cs index b8409a573..cbf1bc3a2 100644 --- a/src/Ryujinx.Graphics.GAL/IPipeline.cs +++ b/src/Ryujinx.Graphics.GAL/IPipeline.cs @@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.GAL void SetIndexBuffer(BufferRange buffer, IndexType type); - void SetImage(ShaderStage stage, int binding, ITexture texture); + 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); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs b/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs index a1e6db971..ef227d4a5 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs @@ -67,6 +67,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading Register(CommandType.CounterEventFlush); Register(CommandType.ImageArrayDispose); + Register(CommandType.ImageArraySetFormats); Register(CommandType.ImageArraySetImages); Register(CommandType.ProgramDispose); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs b/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs index 348c8e462..cf3f5d6c1 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs @@ -27,6 +27,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading CounterEventFlush, ImageArrayDispose, + ImageArraySetFormats, ImageArraySetImages, ProgramDispose, diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArraySetFormatsCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArraySetFormatsCommand.cs new file mode 100644 index 000000000..8e3ba88a8 --- /dev/null +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/ImageArray/ImageArraySetFormatsCommand.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.GAL.Multithreading.Model; +using Ryujinx.Graphics.GAL.Multithreading.Resources; + +namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray +{ + struct ImageArraySetFormatsCommand : IGALCommand, IGALCommand + { + public readonly CommandType CommandType => CommandType.ImageArraySetFormats; + private TableRef _imageArray; + private int _index; + private TableRef _imageFormats; + + public void Set(TableRef imageArray, int index, TableRef 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)); + } + } +} diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs index 2ba9db527..243480a81 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs @@ -10,17 +10,19 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands private ShaderStage _stage; private int _binding; private TableRef _texture; + private Format _imageFormat; - public void Set(ShaderStage stage, int binding, TableRef texture) + public void Set(ShaderStage stage, int binding, TableRef texture, Format imageFormat) { _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(threaded)?.Base); + renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs(threaded)?.Base, command._imageFormat); } } } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs index 82587c189..19bc6f233 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedImageArray.cs @@ -27,6 +27,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources _renderer.QueueCommand(); } + public void SetFormats(int index, Format[] imageFormats) + { + _renderer.New().Set(Ref(this), index, Ref(imageFormats)); + _renderer.QueueCommand(); + } + public void SetImages(int index, ITexture[] images) { _renderer.New().Set(Ref(this), index, Ref(images)); diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs index deec36648..edd79d8a0 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs @@ -177,9 +177,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading _renderer.QueueCommand(); } - public void SetImage(ShaderStage stage, int binding, ITexture texture) + public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat) { - _renderer.New().Set(stage, binding, Ref(texture)); + _renderer.New().Set(stage, binding, Ref(texture), imageFormat); _renderer.QueueCommand(); } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/ShaderTexture.cs b/src/Ryujinx.Graphics.Gpu/Engine/ShaderTexture.cs index bdb34180e..7bff1c4b8 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/ShaderTexture.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/ShaderTexture.cs @@ -1,6 +1,5 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; -using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Shader; namespace Ryujinx.Graphics.Gpu.Engine @@ -62,51 +61,51 @@ namespace Ryujinx.Graphics.Gpu.Engine /// /// Shader image format /// Texture format - public static FormatInfo GetFormatInfo(TextureFormat format) + public static Format GetFormat(TextureFormat format) { return format switch { #pragma warning disable IDE0055 // Disable formatting - 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, + 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, #pragma warning restore IDE0055 }; } diff --git a/src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs b/src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs index b95c684e4..8a9f37bb0 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs @@ -7,11 +7,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// readonly struct FormatInfo { - /// - /// An invalid texture format. - /// - public static FormatInfo Invalid { get; } = new(0, 0, 0, 0, 0); - /// /// A default, generic RGBA8 texture format. /// @@ -28,7 +23,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Must be 1 for non-compressed formats. /// - public byte BlockWidth { get; } + public int BlockWidth { get; } /// /// The block height for compressed formats. @@ -36,17 +31,17 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Must be 1 for non-compressed formats. /// - public byte BlockHeight { get; } + public int BlockHeight { get; } /// /// The number of bytes occupied by a single pixel in memory of the texture data. /// - public byte BytesPerPixel { get; } + public int BytesPerPixel { get; } /// /// The maximum number of components this format has defined (in RGBA order). /// - public byte Components { get; } + public int Components { get; } /// /// Whenever or not the texture format is a compressed format. Determined from block size. @@ -62,10 +57,10 @@ namespace Ryujinx.Graphics.Gpu.Image /// The number of bytes occupied by a single pixel in memory of the texture data public FormatInfo( Format format, - byte blockWidth, - byte blockHeight, - byte bytesPerPixel, - byte components) + int blockWidth, + int blockHeight, + int bytesPerPixel, + int components) { Format = format; BlockWidth = blockWidth; diff --git a/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs b/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs index b007c1591..d6a3d975b 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs @@ -13,11 +13,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// public bool IsDisposed { get; private set; } - /// - /// True if the sampler has sRGB conversion enabled, false otherwise. - /// - public bool IsSrgb { get; } - /// /// Host sampler object. /// @@ -35,8 +30,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// The Maxwell sampler descriptor public Sampler(GpuContext context, SamplerDescriptor descriptor) { - IsSrgb = descriptor.UnpackSrgb(); - MinFilter minFilter = descriptor.UnpackMinFilter(); MagFilter magFilter = descriptor.UnpackMagFilter(); diff --git a/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs b/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs index 836a3260c..e04c31dfa 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs @@ -113,15 +113,6 @@ namespace Ryujinx.Graphics.Gpu.Image return (CompareOp)(((Word0 >> 10) & 7) + 1); } - /// - /// Unpacks the sampler sRGB format flag. - /// - /// True if the has sampler is sRGB conversion enabled, false otherwise - public readonly bool UnpackSrgb() - { - return (Word0 & (1 << 13)) != 0; - } - /// /// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering. /// diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs index e9930405b..31abc21e8 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs @@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// For images, indicates the format specified on the shader. /// - public FormatInfo FormatInfo { get; } + public Format Format { get; } /// /// Shader texture host set index. @@ -58,17 +58,17 @@ namespace Ryujinx.Graphics.Gpu.Image /// Constructs the texture binding information structure. /// /// The shader sampler target type - /// Format of the image as declared on the shader + /// Format of the image as declared on the shader /// Shader texture host set index /// The shader texture binding point /// For array of textures, this indicates the length of the array. A value of one indicates it is not an array /// Constant buffer slot where the texture handle is located /// The shader texture handle (read index into the texture constant buffer) /// The texture's usage flags, indicating how it is used in the shader - public TextureBindingInfo(Target target, FormatInfo formatInfo, int set, 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; - FormatInfo = formatInfo; + Format = format; 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, FormatInfo.Invalid, set, binding, arrayLength, cbufSlot, handle, flags) + bool isSamplerOnly) : this(target, 0, set, binding, arrayLength, cbufSlot, handle, flags) { IsSamplerOnly = isSamplerOnly; } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs index 72bac75e5..8b9243b1e 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs @@ -659,6 +659,7 @@ 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]; @@ -673,7 +674,7 @@ namespace Ryujinx.Graphics.Gpu.Image } else { - ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, bindingInfo.FormatInfo, out texture); + ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, out texture); if (texture != null) { @@ -696,6 +697,8 @@ 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. @@ -703,15 +706,26 @@ namespace Ryujinx.Graphics.Gpu.Image // to ensure we're not using a old buffer that was already deleted. if (isImage) { - _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index); + if (format == 0 && texture != null) + { + format = texture.Format; + } + + _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format); } else { - _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index); + _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format); } } else if (isImage) { + if (format == 0 && texture != null) + { + format = texture.Format; + } + + formats[index] = format; textures[index] = hostTexture; } else @@ -723,6 +737,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (isImage) { + entry.ImageArray.SetFormats(0, formats); entry.ImageArray.SetImages(0, textures); SetImageArray(stage, bindingInfo, entry.ImageArray); @@ -848,6 +863,7 @@ 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]; @@ -867,7 +883,7 @@ namespace Ryujinx.Graphics.Gpu.Image samplerId = TextureHandle.UnpackSamplerId(packedId); } - ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture); + ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture); if (texture != null) { @@ -900,6 +916,8 @@ 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. @@ -907,15 +925,26 @@ namespace Ryujinx.Graphics.Gpu.Image // to ensure we're not using a old buffer that was already deleted. if (isImage) { - _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index); + if (format == 0 && texture != null) + { + format = texture.Format; + } + + _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format); } else { - _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index); + _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format); } } else if (isImage) { + if (format == 0 && texture != null) + { + format = texture.Format; + } + + formats[index] = format; textures[index] = hostTexture; } else @@ -927,6 +956,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (isImage) { + entry.ImageArray.SetFormats(0, formats); entry.ImageArray.SetImages(0, textures); SetImageArray(stage, bindingInfo, entry.ImageArray); diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index f96ddfb1b..9f1f60d95 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -187,9 +187,7 @@ namespace Ryujinx.Graphics.Gpu.Image { (TexturePool texturePool, SamplerPool samplerPool) = GetPools(); - Sampler sampler = samplerPool?.Get(samplerId); - - return (texturePool.Get(textureId, sampler?.IsSrgb ?? true), sampler); + return (texturePool.Get(textureId), samplerPool.Get(samplerId)); } /// @@ -510,12 +508,12 @@ namespace Ryujinx.Graphics.Gpu.Image state.TextureHandle = textureId; state.SamplerHandle = samplerId; - Sampler sampler = samplerPool?.Get(samplerId); - - ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, sampler?.IsSrgb ?? true, out Texture texture); + ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture); specStateMatches &= specState.MatchesTexture(stage, index, descriptor); + Sampler sampler = samplerPool?.Get(samplerId); + ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); ISampler hostSampler = sampler?.GetHostSampler(texture); @@ -524,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, false); + _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, bindingInfo.Format, false); // Cache is not used for buffer texture, it must always rebind. state.CachedTexture = null; @@ -618,7 +616,6 @@ namespace Ryujinx.Graphics.Gpu.Image if (!poolModified && state.TextureHandle == textureId && - state.ImageFormat == bindingInfo.FormatInfo.Format && state.CachedTexture != null && state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence) { @@ -632,22 +629,26 @@ namespace Ryujinx.Graphics.Gpu.Image cachedTexture.SignalModified(); } - if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 && UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)) + Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format; + + if (state.ImageFormat != format || + ((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); + _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind, format); } continue; } state.TextureHandle = textureId; - state.ImageFormat = bindingInfo.FormatInfo.Format; - ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture); + ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, out Texture texture); specStateMatches &= specState.MatchesImage(stage, index, descriptor); @@ -659,7 +660,14 @@ 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. - _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, true); + Format format = bindingInfo.Format; + + if (format == 0 && texture != null) + { + format = texture.Format; + } + + _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, format, true); // Cache is not used for buffer texture, it must always rebind. state.CachedTexture = null; @@ -681,7 +689,16 @@ namespace Ryujinx.Graphics.Gpu.Image { state.Texture = hostTexture; - _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, 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); } state.CachedTexture = texture; diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs index 8bed6363b..3cdeac9c5 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs @@ -739,8 +739,7 @@ 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.R32Uint); + (lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs index be7cb0b89..4ed0a93c1 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -75,76 +75,6 @@ namespace Ryujinx.Graphics.Gpu.Image private readonly ConcurrentQueue _dereferenceQueue = new(); private TextureDescriptor _defaultDescriptor; - /// - /// List of textures that shares the same memory region, but have different formats. - /// - private class TextureAliasList - { - /// - /// Alias texture. - /// - /// Texture format - /// Texture - private readonly record struct Alias(Format Format, Texture Texture); - - /// - /// List of texture aliases. - /// - private readonly List _aliases; - - /// - /// Creates a new instance of the texture alias list. - /// - public TextureAliasList() - { - _aliases = new List(); - } - - /// - /// Adds a new texture alias. - /// - /// Alias format - /// Alias texture - public void Add(Format format, Texture texture) - { - _aliases.Add(new Alias(format, texture)); - texture.IncrementReferenceCount(); - } - - /// - /// Finds a texture with the requested format, or returns null if not found. - /// - /// Format to find - /// Texture with the requested format, or null if not found - public Texture Find(Format format) - { - foreach (var alias in _aliases) - { - if (alias.Format == format) - { - return alias.Texture; - } - } - - return null; - } - - /// - /// Removes all alias textures. - /// - public void Destroy() - { - foreach (var entry in _aliases) - { - entry.Texture.DecrementReferenceCount(); - } - - _aliases.Clear(); - } - } - - private readonly Dictionary _aliasLists; - /// /// Linked list node used on the texture pool cache. /// @@ -165,7 +95,6 @@ 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(); } /// @@ -186,13 +115,14 @@ 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. @@ -227,17 +157,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// ID of the texture. This is effectively a zero-based index /// The texture with the given ID public override Texture Get(int id) - { - return Get(id, srgbSampler: true); - } - - /// - /// Gets the texture with the given ID. - /// - /// ID of the texture. This is effectively a zero-based index - /// Whether the texture is being accessed with a sampler that has sRGB conversion enabled - /// The texture with the given ID - public Texture Get(int id, bool srgbSampler) { if ((uint)id >= Items.Length) { @@ -251,7 +170,7 @@ namespace Ryujinx.Graphics.Gpu.Image SynchronizeMemory(); } - GetForBinding(id, srgbSampler, out Texture texture); + GetInternal(id, out Texture texture); return texture; } @@ -263,10 +182,9 @@ namespace Ryujinx.Graphics.Gpu.Image /// This method assumes that the pool has been manually synchronized before doing binding. /// /// ID of the texture. This is effectively a zero-based index - /// Whether the texture is being accessed with a sampler that has sRGB conversion enabled /// The texture with the given ID /// The texture descriptor with the given ID - public ref readonly TextureDescriptor GetForBinding(int id, bool srgbSampler, out Texture texture) + public ref readonly TextureDescriptor GetForBinding(int id, out Texture texture) { if ((uint)id >= Items.Length) { @@ -276,66 +194,9 @@ namespace Ryujinx.Graphics.Gpu.Image // When getting for binding, assume the pool has already been synchronized. - if (!srgbSampler) - { - // If the sampler does not have the sRGB bit enabled, then the texture can't use a sRGB format. - ref readonly TextureDescriptor tempDescriptor = ref GetDescriptorRef(id); - - if (tempDescriptor.UnpackSrgb() && FormatTable.TryGetTextureFormat(tempDescriptor.UnpackFormat(), isSrgb: false, out FormatInfo formatInfo)) - { - // Get a view of the texture with the right format. - return ref GetForBinding(id, formatInfo, out texture); - } - } - return ref GetInternal(id, out texture); } - /// - /// Gets the texture descriptor and texture with the given ID. - /// - /// - /// This method assumes that the pool has been manually synchronized before doing binding. - /// - /// ID of the texture. This is effectively a zero-based index - /// Texture format information - /// The texture with the given ID - /// The texture descriptor with the given ID - 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; - } - /// /// Checks if the pool was modified, and returns the last sequence number where a modification was detected. /// @@ -373,7 +234,6 @@ namespace Ryujinx.Graphics.Gpu.Image else { texture.DecrementReferenceCount(); - RemoveAliasList(texture); } } @@ -467,8 +327,6 @@ namespace Ryujinx.Graphics.Gpu.Image { texture.DecrementReferenceCount(); } - - RemoveAliasList(texture); } return null; @@ -511,7 +369,6 @@ namespace Ryujinx.Graphics.Gpu.Image if (Interlocked.Exchange(ref Items[id], null) != null) { texture.DecrementReferenceCount(this, id); - RemoveAliasList(texture); } } } @@ -765,57 +622,6 @@ namespace Ryujinx.Graphics.Gpu.Image component == SwizzleComponent.Green; } - /// - /// Changes the format on the texture information structure, and also adjusts the width for the new format if needed. - /// - /// Texture information - /// New format - /// Texture information with the new format - 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); - } - - /// - /// Removes all aliases for a texture. - /// - /// Texture to have the aliases removed - private void RemoveAliasList(Texture texture) - { - if (_aliasLists.TryGetValue(texture, out TextureAliasList aliasList)) - { - _aliasLists.Remove(texture); - aliasList.Destroy(); - } - } - /// /// Decrements the reference count of the texture. /// This indicates that the texture pool is not using it anymore. @@ -823,11 +629,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// The texture to be deleted protected override void Delete(Texture item) { - if (item != null) - { - item.DecrementReferenceCount(this); - RemoveAliasList(item); - } + item?.DecrementReferenceCount(this); } public override void Dispose() diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs index 409867e09..26d9501c6 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs @@ -509,7 +509,7 @@ namespace Ryujinx.Graphics.Gpu.Memory if (binding.IsImage) { - _context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture); + _context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture, binding.Format); } else { @@ -873,11 +873,12 @@ 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, isImage)); + _bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, format, isImage)); } /// @@ -896,11 +897,12 @@ namespace Ryujinx.Graphics.Gpu.Memory ITexture texture, MultiRange range, TextureBindingInfo bindingInfo, - int index) + int index, + Format format) { _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); - _bufferTextureArrays.Add(new BufferTextureArrayBinding(array, texture, range, bindingInfo, index)); + _bufferTextureArrays.Add(new BufferTextureArrayBinding(array, texture, range, bindingInfo, index, format)); } /// @@ -919,11 +921,12 @@ namespace Ryujinx.Graphics.Gpu.Memory ITexture texture, MultiRange range, TextureBindingInfo bindingInfo, - int index) + int index, + Format format) { _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); - _bufferImageArrays.Add(new BufferTextureArrayBinding(array, texture, range, bindingInfo, index)); + _bufferImageArrays.Add(new BufferTextureArrayBinding(array, texture, range, bindingInfo, index, format)); } /// diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureArrayBinding.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureArrayBinding.cs index a5338fa55..fa79e4f92 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureArrayBinding.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureArrayBinding.cs @@ -34,26 +34,33 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public int Index { get; } + /// + /// The image format for the binding. + /// + public Format Format { get; } + /// /// Create a new buffer texture binding. /// - /// Array /// Buffer texture /// Physical ranges of memory where the buffer texture data is located /// Binding info /// Index of the binding on the array + /// Binding format public BufferTextureArrayBinding( T array, ITexture texture, MultiRange range, TextureBindingInfo bindingInfo, - int index) + int index, + Format format) { Array = array; Texture = texture; Range = range; BindingInfo = bindingInfo; Index = index; + Format = format; } } } diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs index 1a3fde5b6..bf0beffa2 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs @@ -30,6 +30,11 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public TextureBindingInfo BindingInfo { get; } + /// + /// The image format for the binding. + /// + public Format Format { get; } + /// /// Whether the binding is for an image or a sampler. /// @@ -42,18 +47,21 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Buffer texture /// Physical ranges of memory where the buffer texture data is located /// Binding info + /// Binding format /// Whether the binding is for an image or a sampler 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; } } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs b/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs index 018c5fdc0..51be00b6e 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs @@ -86,11 +86,11 @@ namespace Ryujinx.Graphics.Gpu.Shader ImageBindings[i] = stage.Info.Images.Select(descriptor => { Target target = ShaderTexture.GetTarget(descriptor.Type); - FormatInfo formatInfo = ShaderTexture.GetFormatInfo(descriptor.Format); + Format format = ShaderTexture.GetFormat(descriptor.Format); var result = new TextureBindingInfo( target, - formatInfo, + format, descriptor.Set, descriptor.Binding, descriptor.ArrayLength, diff --git a/src/Ryujinx.Graphics.Gpu/Window.cs b/src/Ryujinx.Graphics.Gpu/Window.cs index 59cd4c8a6..3b2368537 100644 --- a/src/Ryujinx.Graphics.Gpu/Window.cs +++ b/src/Ryujinx.Graphics.Gpu/Window.cs @@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu bool isLinear, int gobBlocksInY, Format format, - byte bytesPerPixel, + int bytesPerPixel, ImageCrop crop, Action acquireCallback, Action releaseCallback, diff --git a/src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs b/src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs index 3486f29df..6198823d9 100644 --- a/src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs +++ b/src/Ryujinx.Graphics.OpenGL/Image/ImageArray.cs @@ -1,5 +1,6 @@ using OpenTK.Graphics.OpenGL; using Ryujinx.Graphics.GAL; +using System; namespace Ryujinx.Graphics.OpenGL.Image { @@ -18,6 +19,14 @@ 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++) @@ -27,7 +36,6 @@ namespace Ryujinx.Graphics.OpenGL.Image if (image is TextureBase imageBase) { _images[index + i].Handle = imageBase.Handle; - _images[index + i].Format = imageBase.Format; } else { diff --git a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs index 27aacac15..54f6b3f7b 100644 --- a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.OpenGL private readonly Vector4[] _fpIsBgra = new Vector4[SupportBuffer.FragmentIsBgraCount]; - private readonly TextureBase[] _images; + private readonly (TextureBase, Format)[] _images; private TextureBase _unit0Texture; private Sampler _unit0Sampler; @@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL _fragmentOutputMap = uint.MaxValue; _componentMasks = uint.MaxValue; - _images = new TextureBase[SavedImages]; + _images = new (TextureBase, Format)[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) + public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat) { if ((uint)binding < SavedImages) { - _images[binding] = texture as TextureBase; + _images[binding] = (texture as TextureBase, imageFormat); } if (texture == null) @@ -950,7 +950,7 @@ namespace Ryujinx.Graphics.OpenGL TextureBase texBase = (TextureBase)texture; - SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format); + SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); if (format != 0) { @@ -1622,11 +1622,11 @@ namespace Ryujinx.Graphics.OpenGL { for (int i = 0; i < SavedImages; i++) { - TextureBase texBase = _images[i]; + (TextureBase texBase, Format imageFormat) = _images[i]; if (texBase != null) { - SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format); + SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); if (format != 0) { diff --git a/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs b/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs index bcfb3dbfe..a6a006bb9 100644 --- a/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs +++ b/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs @@ -32,12 +32,10 @@ namespace Ryujinx.Graphics.Vulkan CommandBuffer } - private bool _feedbackLoopActive; private PipelineStageFlags _incoherentBufferWriteStages; private PipelineStageFlags _incoherentTextureWriteStages; private PipelineStageFlags _extraStages; private IncoherentBarrierType _queuedIncoherentBarrier; - private bool _queuedFeedbackLoopBarrier; public BarrierBatch(VulkanRenderer gd) { @@ -55,6 +53,17 @@ namespace Ryujinx.Graphics.Vulkan stages |= PipelineStageFlags.TransformFeedbackBitExt; } + if (!gd.IsTBDR) + { + // Desktop GPUs can transform image barriers into memory barriers. + + access |= AccessFlags.DepthStencilAttachmentWriteBit | AccessFlags.ColorAttachmentWriteBit; + access |= AccessFlags.DepthStencilAttachmentReadBit | AccessFlags.ColorAttachmentReadBit; + + stages |= PipelineStageFlags.EarlyFragmentTestsBit | PipelineStageFlags.LateFragmentTestsBit; + stages |= PipelineStageFlags.ColorAttachmentOutputBit; + } + return (access, stages); } @@ -169,34 +178,16 @@ namespace Ryujinx.Graphics.Vulkan } _queuedIncoherentBarrier = IncoherentBarrierType.None; - _queuedFeedbackLoopBarrier = false; } - else if (_feedbackLoopActive && _queuedFeedbackLoopBarrier) - { - // Feedback loop barrier. - - MemoryBarrier barrier = new MemoryBarrier() - { - SType = StructureType.MemoryBarrier, - SrcAccessMask = AccessFlags.ShaderWriteBit, - DstAccessMask = AccessFlags.ShaderReadBit - }; - - QueueBarrier(barrier, PipelineStageFlags.FragmentShaderBit, PipelineStageFlags.AllGraphicsBit); - - _queuedFeedbackLoopBarrier = false; - } - - _feedbackLoopActive = false; } } public unsafe void Flush(CommandBufferScoped cbs, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass) { - Flush(cbs, null, false, inRenderPass, rpHolder, endRenderPass); + Flush(cbs, null, inRenderPass, rpHolder, endRenderPass); } - public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool feedbackLoopActive, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass) + public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass) { if (program != null) { @@ -204,8 +195,6 @@ namespace Ryujinx.Graphics.Vulkan _incoherentTextureWriteStages |= program.IncoherentTextureWriteStages; } - _feedbackLoopActive |= feedbackLoopActive; - FlushMemoryBarrier(program, inRenderPass); if (!inRenderPass && rpHolder != null) @@ -417,8 +406,6 @@ namespace Ryujinx.Graphics.Vulkan { _queuedIncoherentBarrier = type; } - - _queuedFeedbackLoopBarrier = true; } public void QueueTextureBarrier() diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs index 3780dc174..563fdafd3 100644 --- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs @@ -4,7 +4,6 @@ using Ryujinx.Graphics.Shader; using Silk.NET.Vulkan; using System; using System.Buffers; -using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using CompareOp = Ryujinx.Graphics.GAL.CompareOp; @@ -43,15 +42,15 @@ namespace Ryujinx.Graphics.Vulkan private record struct TextureRef { public ShaderStage Stage; - public TextureView View; - public Auto ImageView; + public TextureStorage Storage; + public Auto View; public Auto Sampler; - public TextureRef(ShaderStage stage, TextureView view, Auto imageView, Auto sampler) + public TextureRef(ShaderStage stage, TextureStorage storage, Auto view, Auto sampler) { Stage = stage; + Storage = storage; View = view; - ImageView = imageView; Sampler = sampler; } } @@ -59,14 +58,14 @@ namespace Ryujinx.Graphics.Vulkan private record struct ImageRef { public ShaderStage Stage; - public TextureView View; - public Auto ImageView; + public TextureStorage Storage; + public Auto View; - public ImageRef(ShaderStage stage, TextureView view, Auto imageView) + public ImageRef(ShaderStage stage, TextureStorage storage, Auto view) { Stage = stage; + Storage = storage; View = view; - ImageView = imageView; } } @@ -82,6 +81,7 @@ namespace Ryujinx.Graphics.Vulkan private readonly ImageRef[] _imageRefs; private readonly TextureBuffer[] _bufferTextureRefs; private readonly TextureBuffer[] _bufferImageRefs; + private readonly Format[] _bufferImageFormats; private ArrayRef[] _textureArrayRefs; private ArrayRef[] _imageArrayRefs; @@ -124,8 +124,6 @@ namespace Ryujinx.Graphics.Vulkan private readonly TextureView _dummyTexture; private readonly SamplerHolder _dummySampler; - public List FeedbackLoopHazards { get; private set; } - public DescriptorSetUpdater(VulkanRenderer gd, Device device) { _gd = gd; @@ -140,6 +138,7 @@ 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>(); _imageArrayRefs = Array.Empty>(); @@ -210,15 +209,10 @@ namespace Ryujinx.Graphics.Vulkan _templateUpdater = new(); } - public void Initialize(bool isMainPipeline) + public void Initialize() { MemoryOwner dummyTextureData = MemoryOwner.RentCleared(4); _dummyTexture.SetData(dummyTextureData); - - if (isMainPipeline) - { - FeedbackLoopHazards = new(); - } } private static bool BindingOverlaps(ref DescriptorBufferInfo info, int bindingOffset, int offset, int size) @@ -281,18 +275,6 @@ namespace Ryujinx.Graphics.Vulkan public void InsertBindingBarriers(CommandBufferScoped cbs) { - if ((FeedbackLoopHazards?.Count ?? 0) > 0) - { - // Clear existing hazards - they will be rebuilt. - - foreach (TextureView hazard in FeedbackLoopHazards) - { - hazard.DecrementHazardUses(); - } - - FeedbackLoopHazards.Clear(); - } - foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.TextureSetIndex]) { if (segment.Type == ResourceType.TextureAndSampler) @@ -302,7 +284,7 @@ namespace Ryujinx.Graphics.Vulkan for (int i = 0; i < segment.Count; i++) { ref var texture = ref _textureRefs[segment.Binding + i]; - texture.View?.PrepareForUsage(cbs, texture.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); + texture.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, texture.Stage.ConvertToPipelineStageFlags()); } } else @@ -323,7 +305,7 @@ namespace Ryujinx.Graphics.Vulkan for (int i = 0; i < segment.Count; i++) { ref var image = ref _imageRefs[segment.Binding + i]; - image.View?.PrepareForUsage(cbs, image.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); + image.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, image.Stage.ConvertToPipelineStageFlags()); } } else @@ -389,25 +371,29 @@ namespace Ryujinx.Graphics.Vulkan _dirty = DirtyFlags.All; } - public void SetImage(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture image) + public void SetImage( + CommandBufferScoped cbs, + ShaderStage stage, + int binding, + ITexture image, + Format imageFormat) { if (image is TextureBuffer imageBuffer) { _bufferImageRefs[binding] = imageBuffer; + _bufferImageFormats[binding] = imageFormat; } else if (image is TextureView view) { - ref ImageRef iRef = ref _imageRefs[binding]; + view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags()); - iRef.View?.ClearUsage(FeedbackLoopHazards); - view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); - - iRef = new(stage, view, view.GetIdentityImageView()); + _imageRefs[binding] = new(stage, view.Storage, view.GetView(imageFormat).GetIdentityImageView()); } else { _imageRefs[binding] = default; _bufferImageRefs[binding] = null; + _bufferImageFormats[binding] = default; } SignalDirty(DirtyFlags.Image); @@ -500,12 +486,9 @@ namespace Ryujinx.Graphics.Vulkan } else if (texture is TextureView view) { - ref TextureRef iRef = ref _textureRefs[binding]; + view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags()); - iRef.View?.ClearUsage(FeedbackLoopHazards); - view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); - - iRef = new(stage, view, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler()); + _textureRefs[binding] = new(stage, view.Storage, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler()); } else { @@ -527,7 +510,7 @@ namespace Ryujinx.Graphics.Vulkan { view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags()); - _textureRefs[binding] = new(stage, view, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler()); + _textureRefs[binding] = new(stage, view.Storage, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler()); SignalDirty(DirtyFlags.Texture); } @@ -853,7 +836,7 @@ namespace Ryujinx.Graphics.Vulkan ref var texture = ref textures[i]; ref var refs = ref _textureRefs[binding + i]; - texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default; + texture.ImageView = refs.View?.Get(cbs).Value ?? default; texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default; if (texture.ImageView.Handle == 0) @@ -903,7 +886,7 @@ namespace Ryujinx.Graphics.Vulkan for (int i = 0; i < count; i++) { - images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default; + images[i].ImageView = _imageRefs[binding + i].View?.Get(cbs).Value ?? default; } tu.Push(images[..count]); @@ -914,7 +897,7 @@ namespace Ryujinx.Graphics.Vulkan for (int i = 0; i < count; i++) { - bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, true) ?? default; + bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, _bufferImageFormats[binding + i], true) ?? default; } tu.Push(bufferImages[..count]); @@ -974,7 +957,7 @@ namespace Ryujinx.Graphics.Vulkan ref var texture = ref textures[i]; ref var refs = ref _textureRefs[binding + i]; - texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default; + texture.ImageView = refs.View?.Get(cbs).Value ?? default; texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default; if (texture.ImageView.Handle == 0) diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs index 080dde5e5..c4501ca17 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs @@ -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.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); + _pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs index 26314b7bf..70b3b32a7 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs @@ -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.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); + _pipeline.SetImage(ShaderStage.Compute, 0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs index a8e68f429..6d80f4a49 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs @@ -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.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); + _pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture, 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.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); + _pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture, 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.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); + _pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); diff --git a/src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs b/src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs deleted file mode 100644 index 22f73679d..000000000 --- a/src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Ryujinx.Graphics.Vulkan -{ - [Flags] - internal enum FeedbackLoopAspects - { - None = 0, - Color = 1 << 0, - Depth = 1 << 1, - } -} diff --git a/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs b/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs index 8d80e9d05..763d26eb5 100644 --- a/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs +++ b/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs @@ -302,27 +302,6 @@ namespace Ryujinx.Graphics.Vulkan _depthStencil?.Storage?.AddStoreOpUsage(true); } - public void ClearBindings() - { - _depthStencil?.Storage.ClearBindings(); - - for (int i = 0; i < _colorsCanonical.Length; i++) - { - _colorsCanonical[i]?.Storage.ClearBindings(); - } - } - - public void AddBindings() - { - _depthStencil?.Storage.AddBinding(_depthStencil); - - for (int i = 0; i < _colorsCanonical.Length; i++) - { - TextureView color = _colorsCanonical[i]; - color?.Storage.AddBinding(color); - } - } - public (RenderPassHolder rpHolder, Auto framebuffer) GetPassAndFramebuffer( VulkanRenderer gd, Device device, diff --git a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs index bd17867b1..b6694bcb3 100644 --- a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs +++ b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs @@ -46,8 +46,6 @@ namespace Ryujinx.Graphics.Vulkan public readonly bool SupportsViewportArray2; public readonly bool SupportsHostImportedMemory; public readonly bool SupportsDepthClipControl; - public readonly bool SupportsAttachmentFeedbackLoop; - public readonly bool SupportsDynamicAttachmentFeedbackLoop; public readonly uint SubgroupSize; public readonly SampleCountFlags SupportedSampleCounts; public readonly PortabilitySubsetFlags PortabilitySubset; @@ -86,8 +84,6 @@ namespace Ryujinx.Graphics.Vulkan bool supportsViewportArray2, bool supportsHostImportedMemory, bool supportsDepthClipControl, - bool supportsAttachmentFeedbackLoop, - bool supportsDynamicAttachmentFeedbackLoop, uint subgroupSize, SampleCountFlags supportedSampleCounts, PortabilitySubsetFlags portabilitySubset, @@ -125,8 +121,6 @@ namespace Ryujinx.Graphics.Vulkan SupportsViewportArray2 = supportsViewportArray2; SupportsHostImportedMemory = supportsHostImportedMemory; SupportsDepthClipControl = supportsDepthClipControl; - SupportsAttachmentFeedbackLoop = supportsAttachmentFeedbackLoop; - SupportsDynamicAttachmentFeedbackLoop = supportsDynamicAttachmentFeedbackLoop; SubgroupSize = subgroupSize; SupportedSampleCounts = supportedSampleCounts; PortabilitySubset = portabilitySubset; diff --git a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs index b7c42aff0..73aa95c74 100644 --- a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -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.GetView(dstFormat)); + _pipeline.SetImage(ShaderStage.Compute, 0, dstView, 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.GetView(format)); + _pipeline.SetImage(ShaderStage.Compute, 0, dstView, format); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); diff --git a/src/Ryujinx.Graphics.Vulkan/ImageArray.cs b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs index 019286d28..467b01111 100644 --- a/src/Ryujinx.Graphics.Vulkan/ImageArray.cs +++ b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs @@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Vulkan { public TextureStorage Storage; public TextureView View; + public GAL.Format ImageFormat; } private readonly TextureRef[] _textureRefs; @@ -51,6 +52,16 @@ 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++) @@ -131,7 +142,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) + if (i > 0 && _textureRefs[i - 1].View == refs.View && _textureRefs[i - 1].ImageFormat == refs.ImageFormat) { texture = textures[i - 1]; @@ -139,7 +150,7 @@ namespace Ryujinx.Graphics.Vulkan } texture.ImageLayout = ImageLayout.General; - texture.ImageView = refs.View?.GetIdentityImageView().Get(cbs).Value ?? default; + texture.ImageView = refs.View?.GetView(refs.ImageFormat).GetIdentityImageView().Get(cbs).Value ?? default; if (texture.ImageView.Handle == 0) { @@ -156,7 +167,7 @@ namespace Ryujinx.Graphics.Vulkan for (int i = 0; i < bufferTextures.Length; i++) { - bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, true) ?? default; + bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, _textureRefs[i].ImageFormat, true) ?? default; } return bufferTextures; diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index addad83fd..da5333649 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -2,7 +2,6 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Shader; using Silk.NET.Vulkan; using System; -using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; @@ -34,7 +33,6 @@ namespace Ryujinx.Graphics.Vulkan public readonly Action EndRenderPassDelegate; protected PipelineDynamicState DynamicState; - protected bool IsMainPipeline; private PipelineState _newState; private bool _graphicsStateDirty; private bool _computeStateDirty; @@ -87,9 +85,6 @@ namespace Ryujinx.Graphics.Vulkan private bool _tfEnabled; private bool _tfActive; - private FeedbackLoopAspects _feedbackLoop; - private bool _passWritesDepthStencil; - private readonly PipelineColorBlendAttachmentState[] _storedBlend; public ulong DrawCount { get; private set; } public bool RenderPassActive { get; private set; } @@ -131,7 +126,7 @@ namespace Ryujinx.Graphics.Vulkan public void Initialize() { - _descriptorSetUpdater.Initialize(IsMainPipeline); + _descriptorSetUpdater.Initialize(); QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, new[] { 0, 1, 2, 0, 2, 3 }, 4, false); TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, new[] { int.MinValue, -1, 0 }, 1, true); @@ -819,8 +814,6 @@ namespace Ryujinx.Graphics.Vulkan _newState.DepthTestEnable = depthTest.TestEnable; _newState.DepthWriteEnable = depthTest.WriteEnable; _newState.DepthCompareOp = depthTest.Func.Convert(); - - UpdatePassDepthStencil(); SignalStateChange(); } @@ -836,9 +829,9 @@ namespace Ryujinx.Graphics.Vulkan SignalStateChange(); } - public void SetImage(ShaderStage stage, int binding, ITexture image) + public void SetImage(ShaderStage stage, int binding, ITexture image, Format imageFormat) { - _descriptorSetUpdater.SetImage(Cbs, stage, binding, image); + _descriptorSetUpdater.SetImage(Cbs, stage, binding, image, imageFormat); } public void SetImage(int binding, Auto image) @@ -1086,8 +1079,6 @@ namespace Ryujinx.Graphics.Vulkan _newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert(); _newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert(); _newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert(); - - UpdatePassDepthStencil(); SignalStateChange(); } @@ -1435,23 +1426,7 @@ namespace Ryujinx.Graphics.Vulkan } } - if (IsMainPipeline) - { - FramebufferParams?.ClearBindings(); - } - FramebufferParams = new FramebufferParams(Device, colors, depthStencil); - - if (IsMainPipeline) - { - FramebufferParams.AddBindings(); - - _newState.FeedbackLoopAspects = FeedbackLoopAspects.None; - _bindingBarriersDirty = true; - } - - _passWritesDepthStencil = false; - UpdatePassDepthStencil(); UpdatePipelineAttachmentFormats(); } @@ -1518,82 +1493,11 @@ namespace Ryujinx.Graphics.Vulkan } } - Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate); + Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate); _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute); } - private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects) - { - if (_feedbackLoop != aspects) - { - if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop) - { - DynamicState.SetFeedbackLoop(aspects); - } - else - { - _newState.FeedbackLoopAspects = aspects; - } - - _feedbackLoop = aspects; - - return true; - } - - return false; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool UpdateFeedbackLoop() - { - List hazards = _descriptorSetUpdater.FeedbackLoopHazards; - - if ((hazards?.Count ?? 0) > 0) - { - FeedbackLoopAspects aspects = 0; - - foreach (TextureView view in hazards) - { - // May need to enforce feedback loop layout here in the future. - // Though technically, it should always work with the general layout. - - if (view.Info.Format.IsDepthOrStencil()) - { - if (_passWritesDepthStencil) - { - // If depth/stencil isn't written in the pass, it doesn't count as a feedback loop. - - aspects |= FeedbackLoopAspects.Depth; - } - } - else - { - aspects |= FeedbackLoopAspects.Color; - } - } - - return ChangeFeedbackLoop(aspects); - } - else if (_feedbackLoop != 0) - { - return ChangeFeedbackLoop(FeedbackLoopAspects.None); - } - - return false; - } - - private void UpdatePassDepthStencil() - { - if (!RenderPassActive) - { - _passWritesDepthStencil = false; - } - - // Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check. - _passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable; - } - private bool RecreateGraphicsPipelineIfNeeded() { if (AutoFlush.ShouldFlushDraw(DrawCount)) @@ -1601,7 +1505,7 @@ namespace Ryujinx.Graphics.Vulkan Gd.FlushAllCommands(); } - DynamicState.ReplayIfDirty(Gd, CommandBuffer); + DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer); if (_needsIndexBufferRebind && _indexBufferPattern == null) { @@ -1635,15 +1539,7 @@ namespace Ryujinx.Graphics.Vulkan _vertexBufferUpdater.Commit(Cbs); } - if (_bindingBarriersDirty) - { - // Stale barriers may have been activated by switching program. Emit any that are relevant. - _descriptorSetUpdater.InsertBindingBarriers(Cbs); - - _bindingBarriersDirty = false; - } - - if (UpdateFeedbackLoop() || _graphicsStateDirty || Pbp != PipelineBindPoint.Graphics) + if (_graphicsStateDirty || Pbp != PipelineBindPoint.Graphics) { if (!CreatePipeline(PipelineBindPoint.Graphics)) { @@ -1652,9 +1548,17 @@ namespace Ryujinx.Graphics.Vulkan _graphicsStateDirty = false; Pbp = PipelineBindPoint.Graphics; + + if (_bindingBarriersDirty) + { + // Stale barriers may have been activated by switching program. Emit any that are relevant. + _descriptorSetUpdater.InsertBindingBarriers(Cbs); + + _bindingBarriersDirty = false; + } } - Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate); + Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate); _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics); diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs index ad26ff7b3..1cc33f728 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs @@ -1,6 +1,5 @@ using Ryujinx.Common.Memory; using Silk.NET.Vulkan; -using Silk.NET.Vulkan.Extensions.EXT; namespace Ryujinx.Graphics.Vulkan { @@ -22,8 +21,6 @@ namespace Ryujinx.Graphics.Vulkan private Array4 _blendConstants; - private FeedbackLoopAspects _feedbackLoopAspects; - public uint ViewportsCount; public Array16 Viewports; @@ -35,8 +32,7 @@ namespace Ryujinx.Graphics.Vulkan Scissor = 1 << 2, Stencil = 1 << 3, Viewport = 1 << 4, - FeedbackLoop = 1 << 5, - All = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop, + All = Blend | DepthBias | Scissor | Stencil | Viewport, } private DirtyFlags _dirty; @@ -103,22 +99,13 @@ namespace Ryujinx.Graphics.Vulkan } } - public void SetFeedbackLoop(FeedbackLoopAspects aspects) - { - _feedbackLoopAspects = aspects; - - _dirty |= DirtyFlags.FeedbackLoop; - } - public void ForceAllDirty() { _dirty = DirtyFlags.All; } - public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer) + public void ReplayIfDirty(Vk api, CommandBuffer commandBuffer) { - Vk api = gd.Api; - if (_dirty.HasFlag(DirtyFlags.Blend)) { RecordBlend(api, commandBuffer); @@ -144,11 +131,6 @@ namespace Ryujinx.Graphics.Vulkan RecordViewport(api, commandBuffer); } - if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop) - { - RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer); - } - _dirty = DirtyFlags.None; } @@ -187,17 +169,5 @@ namespace Ryujinx.Graphics.Vulkan api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan()); } } - - private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer) - { - ImageAspectFlags aspects = (_feedbackLoopAspects & FeedbackLoopAspects.Color) != 0 ? ImageAspectFlags.ColorBit : 0; - - if ((_feedbackLoopAspects & FeedbackLoopAspects.Depth) != 0) - { - aspects |= ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit; - } - - api.CmdSetAttachmentFeedbackLoopEnable(commandBuffer, aspects); - } } } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs b/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs index 54d43bdba..cf65eefb0 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs @@ -28,8 +28,6 @@ namespace Ryujinx.Graphics.Vulkan _activeBufferMirrors = new(); CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer; - - IsMainPipeline = true; } private void CopyPendingQuery() @@ -237,7 +235,7 @@ namespace Ryujinx.Graphics.Vulkan if (Pipeline != null && Pbp == PipelineBindPoint.Graphics) { - DynamicState.ReplayIfDirty(Gd, CommandBuffer); + DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer); } } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index a726b9edb..6b6b46a91 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -8,7 +8,6 @@ namespace Ryujinx.Graphics.Vulkan struct PipelineState : IDisposable { private const int RequiredSubgroupSize = 32; - private const int MaxDynamicStatesCount = 9; public PipelineUid Internal; @@ -300,12 +299,6 @@ namespace Ryujinx.Graphics.Vulkan set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6); } - public FeedbackLoopAspects FeedbackLoopAspects - { - readonly get => (FeedbackLoopAspects)((Internal.Id8 >> 7) & 0x3); - set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFE7F) | (((ulong)value) << 7); - } - public bool HasTessellationControlShader; public NativeArray Stages; public PipelineLayout PipelineLayout; @@ -571,11 +564,9 @@ namespace Ryujinx.Graphics.Vulkan } bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState; - bool supportsFeedbackLoopDynamicState = gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop; + int dynamicStatesCount = supportsExtDynamicState ? 8 : 7; - DynamicState* dynamicStates = stackalloc DynamicState[MaxDynamicStatesCount]; - - int dynamicStatesCount = 7; + DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount]; dynamicStates[0] = DynamicState.Viewport; dynamicStates[1] = DynamicState.Scissor; @@ -587,12 +578,7 @@ namespace Ryujinx.Graphics.Vulkan if (supportsExtDynamicState) { - dynamicStates[dynamicStatesCount++] = DynamicState.VertexInputBindingStrideExt; - } - - if (supportsFeedbackLoopDynamicState) - { - dynamicStates[dynamicStatesCount++] = DynamicState.AttachmentFeedbackLoopEnableExt; + dynamicStates[7] = DynamicState.VertexInputBindingStrideExt; } var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo @@ -602,27 +588,9 @@ namespace Ryujinx.Graphics.Vulkan PDynamicStates = dynamicStates, }; - PipelineCreateFlags flags = 0; - - if (gd.Capabilities.SupportsAttachmentFeedbackLoop) - { - FeedbackLoopAspects aspects = FeedbackLoopAspects; - - if ((aspects & FeedbackLoopAspects.Color) != 0) - { - flags |= PipelineCreateFlags.CreateColorAttachmentFeedbackLoopBitExt; - } - - if ((aspects & FeedbackLoopAspects.Depth) != 0) - { - flags |= PipelineCreateFlags.CreateDepthStencilAttachmentFeedbackLoopBitExt; - } - } - var pipelineCreateInfo = new GraphicsPipelineCreateInfo { SType = StructureType.GraphicsPipelineCreateInfo, - Flags = flags, StageCount = StagesCount, PStages = Stages.Pointer, PVertexInputState = &vertexInputState, diff --git a/src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs b/src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs index 073eee2ca..5a4f4215d 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureBuffer.cs @@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Vulkan private int _offset; private int _size; private Auto _bufferView; + private Dictionary> _selfManagedViews; private int _bufferCount; @@ -79,6 +80,16 @@ namespace Ryujinx.Graphics.Vulkan private void ReleaseImpl() { + if (_selfManagedViews != null) + { + foreach (var bufferView in _selfManagedViews.Values) + { + bufferView.Dispose(); + } + + _selfManagedViews = null; + } + _bufferView?.Dispose(); _bufferView = null; } @@ -126,5 +137,28 @@ 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>()).Add(format, bufferView); + } + + return bufferView?.Get(cbs, _offset, _size, write).Value ?? default; + } } } diff --git a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs index 10b36a3f9..f78b9ed47 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs @@ -4,7 +4,6 @@ using Silk.NET.Vulkan; using System; using System.Collections.Generic; using System.Numerics; -using System.Runtime.CompilerServices; using Format = Ryujinx.Graphics.GAL.Format; using VkBuffer = Silk.NET.Vulkan.Buffer; using VkFormat = Silk.NET.Vulkan.Format; @@ -13,11 +12,6 @@ namespace Ryujinx.Graphics.Vulkan { class TextureStorage : IDisposable { - private struct TextureSliceInfo - { - public int BindCount; - } - private const MemoryPropertyFlags DefaultImageMemoryFlags = MemoryPropertyFlags.DeviceLocalBit; @@ -49,7 +43,6 @@ namespace Ryujinx.Graphics.Vulkan private readonly Image _image; private readonly Auto _imageAuto; private readonly Auto _allocationAuto; - private readonly int _depthOrLayers; private Auto _foreignAllocationAuto; private Dictionary _aliasedStorages; @@ -62,9 +55,6 @@ namespace Ryujinx.Graphics.Vulkan private int _viewsCount; private readonly ulong _size; - private int _bindCount; - private readonly TextureSliceInfo[] _slices; - public VkFormat VkFormat { get; } public unsafe TextureStorage( @@ -83,7 +73,6 @@ namespace Ryujinx.Graphics.Vulkan var depth = (uint)(info.Target == Target.Texture3D ? info.Depth : 1); VkFormat = format; - _depthOrLayers = info.GetDepthOrLayers(); var type = info.Target.Convert(); @@ -91,7 +80,7 @@ namespace Ryujinx.Graphics.Vulkan var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples); - var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities); + var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample); var flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit; @@ -159,8 +148,6 @@ namespace Ryujinx.Graphics.Vulkan InitialTransition(ImageLayout.Preinitialized, ImageLayout.General); } - - _slices = new TextureSliceInfo[levels * _depthOrLayers]; } public TextureStorage CreateAliasedColorForDepthStorageUnsafe(Format format) @@ -305,7 +292,7 @@ namespace Ryujinx.Graphics.Vulkan } } - public static ImageUsageFlags GetImageUsage(Format format, Target target, in HardwareCapabilities capabilities) + public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage) { var usage = DefaultUsageFlags; @@ -318,19 +305,11 @@ namespace Ryujinx.Graphics.Vulkan usage |= ImageUsageFlags.ColorAttachmentBit; } - bool supportsMsStorage = capabilities.SupportsShaderStorageImageMultisample; - if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample())) { usage |= ImageUsageFlags.StorageBit; } - if (capabilities.SupportsAttachmentFeedbackLoop && - (usage & (ImageUsageFlags.DepthStencilAttachmentBit | ImageUsageFlags.ColorAttachmentBit)) != 0) - { - usage |= ImageUsageFlags.AttachmentFeedbackLoopBitExt; - } - return usage; } @@ -531,55 +510,6 @@ namespace Ryujinx.Graphics.Vulkan } } - public void AddBinding(TextureView view) - { - // Assumes a view only has a first level. - - int index = view.FirstLevel * _depthOrLayers + view.FirstLayer; - int layers = view.Layers; - - for (int i = 0; i < layers; i++) - { - ref TextureSliceInfo info = ref _slices[index++]; - - info.BindCount++; - } - - _bindCount++; - } - - public void ClearBindings() - { - if (_bindCount != 0) - { - Array.Clear(_slices, 0, _slices.Length); - - _bindCount = 0; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsBound(TextureView view) - { - if (_bindCount != 0) - { - int index = view.FirstLevel * _depthOrLayers + view.FirstLayer; - int layers = view.Layers; - - for (int i = 0; i < layers; i++) - { - ref TextureSliceInfo info = ref _slices[index++]; - - if (info.BindCount != 0) - { - return true; - } - } - } - - return false; - } - public void IncrementViewsCount() { _viewsCount++; diff --git a/src/Ryujinx.Graphics.Vulkan/TextureView.cs b/src/Ryujinx.Graphics.Vulkan/TextureView.cs index b7b936809..bbc205164 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureView.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureView.cs @@ -23,8 +23,6 @@ namespace Ryujinx.Graphics.Vulkan private readonly Auto _imageView2dArray; private Dictionary _selfManagedViews; - private int _hazardUses; - private readonly TextureCreateInfo _info; private HashTableSlim _renderPasses; @@ -62,7 +60,7 @@ namespace Ryujinx.Graphics.Vulkan gd.Textures.Add(this); var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format); - var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities); + var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample); var levels = (uint)info.Levels; var layers = (uint)info.GetLayers(); @@ -1036,34 +1034,6 @@ namespace Ryujinx.Graphics.Vulkan throw new NotImplementedException(); } - public void PrepareForUsage(CommandBufferScoped cbs, PipelineStageFlags flags, List feedbackLoopHazards) - { - Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, flags); - - if (feedbackLoopHazards != null && Storage.IsBound(this)) - { - feedbackLoopHazards.Add(this); - _hazardUses++; - } - } - - public void ClearUsage(List feedbackLoopHazards) - { - if (_hazardUses != 0 && feedbackLoopHazards != null) - { - feedbackLoopHazards.Remove(this); - _hazardUses--; - } - } - - public void DecrementHazardUses() - { - if (_hazardUses != 0) - { - _hazardUses--; - } - } - public (RenderPassHolder rpHolder, Auto framebuffer) GetPassAndFramebuffer( VulkanRenderer gd, Device device, diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index 2c327fdb7..5a9844cb9 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -44,8 +44,6 @@ namespace Ryujinx.Graphics.Vulkan "VK_EXT_4444_formats", "VK_KHR_8bit_storage", "VK_KHR_maintenance2", - "VK_EXT_attachment_feedback_loop_layout", - "VK_EXT_attachment_feedback_loop_dynamic_state", }; private static readonly string[] _requiredExtensions = { @@ -359,28 +357,6 @@ namespace Ryujinx.Graphics.Vulkan features2.PNext = &supportedFeaturesDepthClipControl; } - PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT supportedFeaturesAttachmentFeedbackLoopLayout = new() - { - SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt, - PNext = features2.PNext, - }; - - if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout")) - { - features2.PNext = &supportedFeaturesAttachmentFeedbackLoopLayout; - } - - PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT supportedFeaturesDynamicAttachmentFeedbackLoopLayout = new() - { - SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt, - PNext = features2.PNext, - }; - - if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state")) - { - features2.PNext = &supportedFeaturesDynamicAttachmentFeedbackLoopLayout; - } - PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new() { SType = StructureType.PhysicalDeviceVulkan12Features, @@ -555,36 +531,6 @@ namespace Ryujinx.Graphics.Vulkan pExtendedFeatures = &featuresDepthClipControl; } - PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoopLayout; - - if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout") && - supportedFeaturesAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopLayout) - { - featuresAttachmentFeedbackLoopLayout = new() - { - SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt, - PNext = pExtendedFeatures, - AttachmentFeedbackLoopLayout = true, - }; - - pExtendedFeatures = &featuresAttachmentFeedbackLoopLayout; - } - - PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoopLayout; - - if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state") && - supportedFeaturesDynamicAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopDynamicState) - { - featuresDynamicAttachmentFeedbackLoopLayout = new() - { - SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt, - PNext = pExtendedFeatures, - AttachmentFeedbackLoopDynamicState = true, - }; - - pExtendedFeatures = &featuresDynamicAttachmentFeedbackLoopLayout; - } - var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray(); IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length]; diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 0faaec82a..f51fab646 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -38,7 +38,6 @@ namespace Ryujinx.Graphics.Vulkan internal KhrPushDescriptor PushDescriptorApi { get; private set; } internal ExtTransformFeedback TransformFeedbackApi { get; private set; } internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; } - internal ExtAttachmentFeedbackLoopDynamicState DynamicFeedbackLoopApi { get; private set; } internal uint QueueFamilyIndex { get; private set; } internal Queue Queue { get; private set; } @@ -150,11 +149,6 @@ namespace Ryujinx.Graphics.Vulkan DrawIndirectCountApi = drawIndirectCountApi; } - if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtAttachmentFeedbackLoopDynamicState dynamicFeedbackLoopApi)) - { - DynamicFeedbackLoopApi = dynamicFeedbackLoopApi; - } - if (maxQueueCount >= 2) { Api.GetDeviceQueue(_device, queueFamilyIndex, 1, out var backgroundQueue); @@ -249,16 +243,6 @@ namespace Ryujinx.Graphics.Vulkan SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt, }; - PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoop = new() - { - SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt, - }; - - PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoop = new() - { - SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt, - }; - PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new() { SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr, @@ -295,22 +279,6 @@ namespace Ryujinx.Graphics.Vulkan features2.PNext = &featuresDepthClipControl; } - bool supportsAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout"); - - if (supportsAttachmentFeedbackLoop) - { - featuresAttachmentFeedbackLoop.PNext = features2.PNext; - features2.PNext = &featuresAttachmentFeedbackLoop; - } - - bool supportsDynamicAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state"); - - if (supportsDynamicAttachmentFeedbackLoop) - { - featuresDynamicAttachmentFeedbackLoop.PNext = features2.PNext; - features2.PNext = &featuresDynamicAttachmentFeedbackLoop; - } - bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset"); if (usePortability) @@ -433,8 +401,6 @@ namespace Ryujinx.Graphics.Vulkan _physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"), _physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName), supportsDepthClipControl && featuresDepthClipControl.DepthClipControl, - supportsAttachmentFeedbackLoop && featuresAttachmentFeedbackLoop.AttachmentFeedbackLoopLayout, - supportsDynamicAttachmentFeedbackLoop && featuresDynamicAttachmentFeedbackLoop.AttachmentFeedbackLoopDynamicState, propertiesSubgroup.SubgroupSize, supportedSampleCounts, portabilityFlags, diff --git a/src/Ryujinx.Gtk3/Program.cs b/src/Ryujinx.Gtk3/Program.cs index 2d350374b..8bad1a0c7 100644 --- a/src/Ryujinx.Gtk3/Program.cs +++ b/src/Ryujinx.Gtk3/Program.cs @@ -4,7 +4,6 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.Logging; using Ryujinx.Common.SystemInterop; -using Ryujinx.Common.Utilities; using Ryujinx.Graphics.Vulkan.MoltenVK; using Ryujinx.Modules; using Ryujinx.SDL2.Common; @@ -42,6 +41,9 @@ namespace Ryujinx [LibraryImport("user32.dll", SetLastError = true)] public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type); + [LibraryImport("libc", SetLastError = true)] + private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite); + private const uint MbIconWarning = 0x30; static Program() @@ -103,7 +105,8 @@ namespace Ryujinx throw new NotSupportedException("Failed to initialize multi-threading support."); } - OsUtils.SetEnvironmentVariableNoCaching("GDK_BACKEND", "x11"); + Environment.SetEnvironmentVariable("GDK_BACKEND", "x11"); + setenv("GDK_BACKEND", "x11", 1); } if (OperatingSystem.IsMacOS()) @@ -122,13 +125,19 @@ namespace Ryujinx resourcesDataDir = baseDirectory; } + static void SetEnvironmentVariableNoCaching(string key, string value) + { + int res = setenv(key, value, 1); + Debug.Assert(res != -1); + } + // On macOS, GTK3 needs XDG_DATA_DIRS to be set, otherwise it will try searching for "gschemas.compiled" in system directories. - OsUtils.SetEnvironmentVariableNoCaching("XDG_DATA_DIRS", Path.Combine(resourcesDataDir, "share")); + SetEnvironmentVariableNoCaching("XDG_DATA_DIRS", Path.Combine(resourcesDataDir, "share")); // On macOS, GTK3 needs GDK_PIXBUF_MODULE_FILE to be set, otherwise it will try searching for "loaders.cache" in system directories. - OsUtils.SetEnvironmentVariableNoCaching("GDK_PIXBUF_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gdk-pixbuf-2.0", "2.10.0", "loaders.cache")); + SetEnvironmentVariableNoCaching("GDK_PIXBUF_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gdk-pixbuf-2.0", "2.10.0", "loaders.cache")); - OsUtils.SetEnvironmentVariableNoCaching("GTK_IM_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gtk-3.0", "3.0.0", "immodules.cache")); + SetEnvironmentVariableNoCaching("GTK_IM_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gtk-3.0", "3.0.0", "immodules.cache")); } string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); @@ -224,9 +233,9 @@ namespace Ryujinx // Logging system information. PrintSystemInfo(); - // Enable OGL multithreading on the driver, and some other flags. + // Enable OGL multithreading on the driver, when available. BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; - DriverUtilities.InitDriverConfig(threadingMode == BackendThreading.Off); + DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off); // Initialize Gtk. Application.Init(); diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs index 4c17e7aed..fd517b1ae 100644 --- a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs @@ -412,9 +412,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat); - byte bytesPerPixel = + int bytesPerPixel = format == Format.B5G6R5Unorm || - format == Format.R4G4B4A4Unorm ? (byte)2 : (byte)4; + format == Format.R4G4B4A4Unorm ? 2 : 4; int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2; diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs index 4ee271203..871cf0256 100644 --- a/src/Ryujinx.Headless.SDL2/Program.cs +++ b/src/Ryujinx.Headless.SDL2/Program.cs @@ -7,7 +7,6 @@ using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller.Motion; using Ryujinx.Common.Configuration.Hid.Keyboard; -using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.Logging; using Ryujinx.Common.Logging.Targets; using Ryujinx.Common.SystemInterop; @@ -464,8 +463,6 @@ namespace Ryujinx.Headless.SDL2 GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath; GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE; - DriverUtilities.InitDriverConfig(option.BackendThreading == BackendThreading.Off); - while (true) { LoadApplication(option); diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs index 6c83cedcf..af9db7d63 100644 --- a/src/Ryujinx/Program.cs +++ b/src/Ryujinx/Program.cs @@ -117,8 +117,8 @@ namespace Ryujinx.Ava // Logging system information. PrintSystemInfo(); - // Enable OGL multithreading on the driver, and some other flags. - DriverUtilities.InitDriverConfig(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off); + // Enable OGL multithreading on the driver, when available. + DriverUtilities.ToggleOGLThreading(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off); // Check if keys exists. if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))