From caea82cbb4ce396144fe57ff3e8b4c2b4d3c5d8b Mon Sep 17 00:00:00 2001 From: The Roofer Dev Date: Sun, 28 Jun 2026 21:41:25 -0400 Subject: [PATCH] TAA Phase 5: expose native TAA in the UI (Anti-Aliasing dropdown) Adds AntiAliasing.Taa and a 'TAA' entry to Settings > Graphics > Anti-Aliasing, so the native temporal AA is a normal user-selectable option alongside FXAA/SMAA (it is a post-process effect, not a scaling filter). Selecting it instantiates TemporalFilter as the active IPostProcessingEffect; applies live, no restart. RYUJINX_TAA=1 still force-enables it as a dev override. On the OpenGL backend TAA falls back to no AA (Vulkan-only feature). Validated in game via the UI. Bakes the in-game-validated defaults so UI users get the tuned look with no env vars: history blend 0.80, variance clamp 1.25 (RYUJINX_TAA_* still override). --- .../Configuration/AntiAliasing.cs | 1 + src/Ryujinx.Graphics.OpenGL/Window.cs | 1 + .../Effects/TemporalFilter.cs | 12 +++++----- src/Ryujinx.Graphics.Vulkan/Window.cs | 22 +++++++++---------- .../Views/Settings/SettingsGraphicsView.axaml | 2 ++ 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Ryujinx.Common/Configuration/AntiAliasing.cs b/src/Ryujinx.Common/Configuration/AntiAliasing.cs index 1510c23ee..f6cdc39f9 100644 --- a/src/Ryujinx.Common/Configuration/AntiAliasing.cs +++ b/src/Ryujinx.Common/Configuration/AntiAliasing.cs @@ -11,5 +11,6 @@ namespace Ryujinx.Common.Configuration SmaaMedium, SmaaHigh, SmaaUltra, + Taa, } } diff --git a/src/Ryujinx.Graphics.OpenGL/Window.cs b/src/Ryujinx.Graphics.OpenGL/Window.cs index 281fae7e7..c597e2d30 100644 --- a/src/Ryujinx.Graphics.OpenGL/Window.cs +++ b/src/Ryujinx.Graphics.OpenGL/Window.cs @@ -324,6 +324,7 @@ namespace Ryujinx.Graphics.OpenGL _antiAliasing = new FxaaPostProcessingEffect(_renderer); break; case AntiAliasing.None: + case AntiAliasing.Taa: // TAA is a Vulkan-only effect; on the GL backend it falls back to no AA. _antiAliasing?.Dispose(); _antiAliasing = null; break; diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/TemporalFilter.cs b/src/Ryujinx.Graphics.Vulkan/Effects/TemporalFilter.cs index 9260b3dff..6d577a322 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/TemporalFilter.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/TemporalFilter.cs @@ -20,10 +20,10 @@ namespace Ryujinx.Graphics.Vulkan.Effects /// the dominant cost), then the field is bilinear-upscaled and scaled by N when the blend reprojects the /// history. Motion estimation is self-contained (reuses the DLSS shaders) so TAA works with DLSS off. /// - /// Gated entirely on RYUJINX_TAA=1: when unset the present path never constructs or runs this, so the - /// default render is byte-identical. Tunables (no rebuild): RYUJINX_TAA_BLEND (history weight, default - /// 0.90), RYUJINX_TAA_MV_SIGN (reprojection direction, default +1), RYUJINX_TAA_CLAMP (variance-box - /// half-width in std-devs, default 1.0), RYUJINX_TAA_MV_DOWNSCALE (flow resolution divisor 1/2/4, default 2). + /// Selected from the UI as an Anti-Aliasing option (AntiAliasing.Taa); RYUJINX_TAA=1 also force-enables it + /// (dev override). Tunables (no rebuild): RYUJINX_TAA_BLEND (history weight, default 0.80), RYUJINX_TAA_MV_SIGN + /// (reprojection direction, default +1), RYUJINX_TAA_CLAMP (variance-box half-width in std-devs, default 1.25), + /// RYUJINX_TAA_MV_DOWNSCALE (flow resolution divisor 1/2/4, default 2). /// internal class TemporalFilter : IPostProcessingEffect { @@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects return blend; } - return 0.90f; + return 0.80f; // validated in-game default (sharp + steady); RYUJINX_TAA_BLEND overrides. } private static float ParseSign() @@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects return gamma; } - return 1.0f; + return 1.25f; // validated in-game default (lets native texture detail through); RYUJINX_TAA_CLAMP overrides. } private static int ParseDownscale() diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs index 0466bf87a..264528ad2 100644 --- a/src/Ryujinx.Graphics.Vulkan/Window.cs +++ b/src/Ryujinx.Graphics.Vulkan/Window.cs @@ -37,7 +37,6 @@ namespace Ryujinx.Graphics.Vulkan private bool _updateEffect; private IPostProcessingEffect _effect; private IScalingFilter _scalingFilter; - private Effects.TemporalFilter _taa; private Dlss.DlssUpscaler _dlss; private bool _isLinear; private float _scalingFilterLevel; @@ -395,14 +394,6 @@ namespace Ryujinx.Graphics.Vulkan view = _effect.Run(view, cbs, _width, _height); } - // Native temporal anti-aliasing (clean-room), gated on RYUJINX_TAA=1. Runs at render resolution - // before the spatial upscale/blit, like a post-processing effect. Phase 0 is a pass-through. - if (Effects.TemporalFilter.IsEnabled) - { - _taa ??= new Effects.TemporalFilter(_gd, _device); - view = _taa.Run(view, cbs, _width, _height); - } - int srcX0, srcX1, srcY0, srcY1; if (crop.Left == 0 && crop.Right == 0) @@ -615,12 +606,22 @@ namespace Ryujinx.Graphics.Vulkan { _updateEffect = false; - switch (_currentAntiAliasing) + // RYUJINX_TAA=1 forces the native temporal filter regardless of the UI selection (dev override). + AntiAliasing antiAliasing = Effects.TemporalFilter.IsEnabled ? AntiAliasing.Taa : _currentAntiAliasing; + + switch (antiAliasing) { case AntiAliasing.Fxaa: _effect?.Dispose(); _effect = new FxaaPostProcessingEffect(_gd, _device); break; + case AntiAliasing.Taa: + if (_effect is not Effects.TemporalFilter) + { + _effect?.Dispose(); + _effect = new Effects.TemporalFilter(_gd, _device); + } + break; case AntiAliasing.None: _effect?.Dispose(); _effect = null; @@ -791,7 +792,6 @@ namespace Ryujinx.Graphics.Vulkan _effect?.Dispose(); _scalingFilter?.Dispose(); - _taa?.Dispose(); _dlss?.Dispose(); } } diff --git a/src/Ryujinx/UI/Views/Settings/SettingsGraphicsView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsGraphicsView.axaml index daf7a08dd..7b3c471cf 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsGraphicsView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsGraphicsView.axaml @@ -290,6 +290,8 @@ Content="{ext:Locale SmaaHigh}" /> +