diff --git a/.editorconfig b/.editorconfig index e5a5e6174c..9d695c7fb0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,13 @@ tab_width = 4 end_of_line = lf insert_final_newline = true +# JSON files +[*.json] + +# Indentation and spacing +indent_size = 2 +tab_width = 2 + # C# files [*.cs] diff --git a/src/Ryujinx.Ava/AppHost.cs b/src/Ryujinx.Ava/AppHost.cs index 7c1ce542c5..786b450707 100644 --- a/src/Ryujinx.Ava/AppHost.cs +++ b/src/Ryujinx.Ava/AppHost.cs @@ -186,6 +186,7 @@ namespace Ryujinx.Ava ConfigurationState.Instance.Graphics.AntiAliasing.Event += UpdateAntiAliasing; ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter; ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel; + ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough; ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState; @@ -229,6 +230,11 @@ namespace Ryujinx.Ava _renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value); } + private void UpdateColorSpacePassthrough(object sender, ReactiveEventArgs e) + { + _renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value); + } + private void ShowCursor() { Dispatcher.UIThread.Post(() => @@ -461,6 +467,7 @@ namespace Ryujinx.Ava ConfigurationState.Instance.Graphics.ScalingFilter.Event -= UpdateScalingFilter; ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event -= UpdateScalingFilterLevel; ConfigurationState.Instance.Graphics.AntiAliasing.Event -= UpdateAntiAliasing; + ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event -= UpdateColorSpacePassthrough; _topLevel.PointerMoved -= TopLevel_PointerEnterOrMoved; _topLevel.PointerEnter -= TopLevel_PointerEnterOrMoved; @@ -887,6 +894,7 @@ namespace Ryujinx.Ava _renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)ConfigurationState.Instance.Graphics.AntiAliasing.Value); _renderer?.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value); _renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value); + _renderer?.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value); Width = (int)RendererHost.Bounds.Width; Height = (int)RendererHost.Bounds.Height; diff --git a/src/Ryujinx.Ava/Assets/Locales/en_US.json b/src/Ryujinx.Ava/Assets/Locales/en_US.json index 4065a1dfbe..efd3187ad4 100644 --- a/src/Ryujinx.Ava/Assets/Locales/en_US.json +++ b/src/Ryujinx.Ava/Assets/Locales/en_US.json @@ -620,6 +620,8 @@ "SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:", "SettingsEnableMacroHLE": "Enable Macro HLE", "SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.", + "SettingsEnableColorSpacePassthrough": "Color Space Passthrough", + "SettingsEnableColorSpacePassthroughTooltip": "Directs the Vulkan backend to pass through color information without specifying a color space. For users with wide gamut displays, this may result in more vibrant colors, at the cost of color correctness.", "VolumeShort": "Vol", "UserProfilesManageSaves": "Manage Saves", "DeleteUserSave": "Do you want to delete user save for this game?", diff --git a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs index a9eb9c6186..1e6d2734f7 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs @@ -145,6 +145,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool EnableShaderCache { get; set; } public bool EnableTextureRecompression { get; set; } public bool EnableMacroHLE { get; set; } + public bool EnableColorSpacePassthrough { get; set; } public bool EnableFileLog { get; set; } public bool EnableStub { get; set; } public bool EnableInfo { get; set; } @@ -419,6 +420,7 @@ namespace Ryujinx.Ava.UI.ViewModels EnableShaderCache = config.Graphics.EnableShaderCache; EnableTextureRecompression = config.Graphics.EnableTextureRecompression; EnableMacroHLE = config.Graphics.EnableMacroHLE; + EnableColorSpacePassthrough = config.Graphics.EnableColorSpacePassthrough; ResolutionScale = config.Graphics.ResScale == -1 ? 4 : config.Graphics.ResScale - 1; CustomResolutionScale = config.Graphics.ResScaleCustom; MaxAnisotropy = config.Graphics.MaxAnisotropy == -1 ? 0 : (int)(MathF.Log2(config.Graphics.MaxAnisotropy)); @@ -506,6 +508,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.Graphics.EnableShaderCache.Value = EnableShaderCache; config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression; config.Graphics.EnableMacroHLE.Value = EnableMacroHLE; + config.Graphics.EnableColorSpacePassthrough.Value = EnableColorSpacePassthrough; config.Graphics.ResScale.Value = ResolutionScale == 4 ? -1 : ResolutionScale + 1; config.Graphics.ResScaleCustom.Value = CustomResolutionScale; config.Graphics.MaxAnisotropy.Value = MaxAnisotropy == 0 ? -1 : MathF.Pow(2, MaxAnisotropy); diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml index 8e4122f38d..670de69c65 100644 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml +++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml @@ -73,6 +73,10 @@ ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}"> + + + public static bool EnableTextureRecompression = false; + + /// + /// Enables or disables color space passthrough, if available. + /// + public static bool EnableColorSpacePassthrough = false; } #pragma warning restore CA2211 } diff --git a/src/Ryujinx.Graphics.OpenGL/Window.cs b/src/Ryujinx.Graphics.OpenGL/Window.cs index a8e6031b6a..6bcfefa4ed 100644 --- a/src/Ryujinx.Graphics.OpenGL/Window.cs +++ b/src/Ryujinx.Graphics.OpenGL/Window.cs @@ -307,6 +307,8 @@ namespace Ryujinx.Graphics.OpenGL _updateScalingFilter = true; } + public void SetColorSpacePassthrough(bool colorSpacePassthroughEnabled) { } + private void UpdateEffect() { if (_updateEffect) diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs index 6027962cf0..2d0ad664cc 100644 --- a/src/Ryujinx.Graphics.Vulkan/Window.cs +++ b/src/Ryujinx.Graphics.Vulkan/Window.cs @@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Vulkan private int _width; private int _height; private bool _vsyncEnabled; - private bool _vsyncModeChanged; + private bool _swapchainIsDirty; private VkFormat _format; private AntiAliasing _currentAntiAliasing; private bool _updateEffect; @@ -38,6 +38,7 @@ namespace Ryujinx.Graphics.Vulkan private float _scalingFilterLevel; private bool _updateScalingFilter; private ScalingFilter _currentScalingFilter; + private bool _colorSpacePassthroughEnabled; public unsafe Window(VulkanRenderer gd, SurfaceKHR surface, PhysicalDevice physicalDevice, Device device) { @@ -60,7 +61,7 @@ namespace Ryujinx.Graphics.Vulkan private void RecreateSwapchain() { var oldSwapchain = _swapchain; - _vsyncModeChanged = false; + _swapchainIsDirty = false; for (int i = 0; i < _swapchainImageViews.Length; i++) { @@ -106,7 +107,7 @@ namespace Ryujinx.Graphics.Vulkan imageCount = capabilities.MaxImageCount; } - var surfaceFormat = ChooseSwapSurfaceFormat(surfaceFormats); + var surfaceFormat = ChooseSwapSurfaceFormat(surfaceFormats, _colorSpacePassthroughEnabled); var extent = ChooseSwapExtent(capabilities); @@ -178,22 +179,40 @@ namespace Ryujinx.Graphics.Vulkan return new Auto(new DisposableImageView(_gd.Api, _device, imageView)); } - private static SurfaceFormatKHR ChooseSwapSurfaceFormat(SurfaceFormatKHR[] availableFormats) + private static SurfaceFormatKHR ChooseSwapSurfaceFormat(SurfaceFormatKHR[] availableFormats, bool colorSpacePassthroughEnabled) { if (availableFormats.Length == 1 && availableFormats[0].Format == VkFormat.Undefined) { return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, ColorSpaceKHR.PaceSrgbNonlinearKhr); } - - foreach (var format in availableFormats) + var formatToReturn = availableFormats[0]; + if (colorSpacePassthroughEnabled) { - if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.PaceSrgbNonlinearKhr) + foreach (var format in availableFormats) { - return format; + if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.SpacePassThroughExt) + { + formatToReturn = format; + break; + } + else if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.PaceSrgbNonlinearKhr) + { + formatToReturn = format; + } } } - - return availableFormats[0]; + else + { + foreach (var format in availableFormats) + { + if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.PaceSrgbNonlinearKhr) + { + formatToReturn = format; + break; + } + } + } + return formatToReturn; } private static CompositeAlphaFlagsKHR ChooseCompositeAlpha(CompositeAlphaFlagsKHR supportedFlags) @@ -259,7 +278,7 @@ namespace Ryujinx.Graphics.Vulkan if (acquireResult == Result.ErrorOutOfDateKhr || acquireResult == Result.SuboptimalKhr || - _vsyncModeChanged) + _swapchainIsDirty) { RecreateSwapchain(); } @@ -443,6 +462,12 @@ namespace Ryujinx.Graphics.Vulkan _updateScalingFilter = true; } + public override void SetColorSpacePassthrough(bool colorSpacePassthroughEnabled) + { + _colorSpacePassthroughEnabled = colorSpacePassthroughEnabled; + _swapchainIsDirty = true; + } + private void UpdateEffect() { if (_updateEffect) @@ -559,7 +584,7 @@ namespace Ryujinx.Graphics.Vulkan public override void ChangeVSyncMode(bool vsyncEnabled) { _vsyncEnabled = vsyncEnabled; - _vsyncModeChanged = true; + _swapchainIsDirty = true; } protected virtual void Dispose(bool disposing) diff --git a/src/Ryujinx.Graphics.Vulkan/WindowBase.cs b/src/Ryujinx.Graphics.Vulkan/WindowBase.cs index 146cf6607f..da1613f41b 100644 --- a/src/Ryujinx.Graphics.Vulkan/WindowBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/WindowBase.cs @@ -14,5 +14,6 @@ namespace Ryujinx.Graphics.Vulkan public abstract void SetAntiAliasing(AntiAliasing effect); public abstract void SetScalingFilter(ScalingFilter scalerType); public abstract void SetScalingFilterLevel(float scale); + public abstract void SetColorSpacePassthrough(bool colorSpacePassthroughEnabled); } } diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs index 4348943287..09e7f570a6 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs @@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Common.Configuration /// /// The current version of the file format /// - public const int CurrentVersion = 47; + public const int CurrentVersion = 48; /// /// Version of the configuration file format @@ -186,6 +186,11 @@ namespace Ryujinx.Ui.Common.Configuration /// public bool EnableMacroHLE { get; set; } + /// + /// Enables or disables color space passthrough, if available. + /// + public bool EnableColorSpacePassthrough { get; set; } + /// /// Enables or disables profiled translation cache persistency /// diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs index 7ab20e329e..ee898354b3 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs +++ b/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs @@ -485,6 +485,11 @@ namespace Ryujinx.Ui.Common.Configuration /// public ReactiveObject EnableMacroHLE { get; private set; } + /// + /// Enables or disables color space passthrough, if available. + /// + public ReactiveObject EnableColorSpacePassthrough { get; private set; } + /// /// Graphics backend /// @@ -535,6 +540,8 @@ namespace Ryujinx.Ui.Common.Configuration PreferredGpu.Event += static (sender, e) => LogValueChange(e, nameof(PreferredGpu)); EnableMacroHLE = new ReactiveObject(); EnableMacroHLE.Event += static (sender, e) => LogValueChange(e, nameof(EnableMacroHLE)); + EnableColorSpacePassthrough = new ReactiveObject(); + EnableColorSpacePassthrough.Event += static (sender, e) => LogValueChange(e, nameof(EnableColorSpacePassthrough)); AntiAliasing = new ReactiveObject(); AntiAliasing.Event += static (sender, e) => LogValueChange(e, nameof(AntiAliasing)); ScalingFilter = new ReactiveObject(); @@ -667,6 +674,7 @@ namespace Ryujinx.Ui.Common.Configuration EnableShaderCache = Graphics.EnableShaderCache, EnableTextureRecompression = Graphics.EnableTextureRecompression, EnableMacroHLE = Graphics.EnableMacroHLE, + EnableColorSpacePassthrough = Graphics.EnableColorSpacePassthrough, EnablePtc = System.EnablePtc, EnableInternetAccess = System.EnableInternetAccess, EnableFsIntegrityChecks = System.EnableFsIntegrityChecks, @@ -772,6 +780,7 @@ namespace Ryujinx.Ui.Common.Configuration Graphics.EnableShaderCache.Value = true; Graphics.EnableTextureRecompression.Value = false; Graphics.EnableMacroHLE.Value = true; + Graphics.EnableColorSpacePassthrough.Value = false; Graphics.AntiAliasing.Value = AntiAliasing.None; Graphics.ScalingFilter.Value = ScalingFilter.Bilinear; Graphics.ScalingFilterLevel.Value = 80; @@ -1391,6 +1400,15 @@ namespace Ryujinx.Ui.Common.Configuration configurationFileUpdated = true; } + if (configurationFileFormat.Version < 48) + { + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 48."); + + configurationFileFormat.EnableColorSpacePassthrough = false; + + configurationFileUpdated = true; + } + Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; Graphics.ResScale.Value = configurationFileFormat.ResScale; Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom; @@ -1426,6 +1444,7 @@ namespace Ryujinx.Ui.Common.Configuration Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache; Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression; Graphics.EnableMacroHLE.Value = configurationFileFormat.EnableMacroHLE; + Graphics.EnableColorSpacePassthrough.Value = configurationFileFormat.EnableColorSpacePassthrough; System.EnablePtc.Value = configurationFileFormat.EnablePtc; System.EnableInternetAccess.Value = configurationFileFormat.EnableInternetAccess; System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks;