diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index fb4ab007c..da412bdf2 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -380,11 +380,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed if (changedScale) { + float oldScale = _channel.TextureManager.RenderTargetScale; _channel.TextureManager.UpdateRenderTargetScale(singleUse); - _context.Renderer.Pipeline.SetRenderTargetScale(_channel.TextureManager.RenderTargetScale); - UpdateViewportTransform(); - UpdateScissorState(); + if (oldScale != _channel.TextureManager.RenderTargetScale) + { + _context.Renderer.Pipeline.SetRenderTargetScale(_channel.TextureManager.RenderTargetScale); + + UpdateViewportTransform(); + UpdateScissorState(); + } } } diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index a3105cf28..e156ff5ed 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -549,7 +549,8 @@ namespace Ryujinx.Graphics.Gpu.Image /// The new scale factor for this texture public void SetScale(float scale) { - TextureScaleMode newScaleMode = ScaleMode == TextureScaleMode.Blacklisted ? ScaleMode : TextureScaleMode.Scaled; + bool unscaled = ScaleMode == TextureScaleMode.Blacklisted || (ScaleMode == TextureScaleMode.Undesired && scale == 1); + TextureScaleMode newScaleMode = unscaled ? ScaleMode : TextureScaleMode.Scaled; if (_viewStorage != this) { diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index d9920f973..58cd3a2f7 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -87,10 +87,16 @@ namespace Ryujinx.Graphics.Gpu.Image /// Determines if a given texture is eligible for upscaling from its info. /// /// The texture info to check + /// True if the user of the texture would prefer it to be upscaled immediately /// True if eligible - private static bool IsUpscaleCompatible(TextureInfo info) + private static TextureScaleMode IsUpscaleCompatible(TextureInfo info, bool withUpscale) { - return (info.Target == Target.Texture2D || info.Target == Target.Texture2DArray) && !info.FormatInfo.IsCompressed && UpscaleSafeMode(info); + if ((info.Target == Target.Texture2D || info.Target == Target.Texture2DArray) && !info.FormatInfo.IsCompressed) + { + return UpscaleSafeMode(info) ? (withUpscale ? TextureScaleMode.Scaled : TextureScaleMode.Eligible) : TextureScaleMode.Undesired; + } + + return TextureScaleMode.Blacklisted; } /// @@ -117,13 +123,13 @@ namespace Ryujinx.Graphics.Gpu.Image return false; } + int widthAlignment = (info.IsLinear ? Constants.StrideAlignment : Constants.GobAlignment) / info.FormatInfo.BytesPerPixel; + if (!(info.FormatInfo.Format.IsDepthOrStencil() || info.FormatInfo.Components == 1)) { // Discount square textures that aren't depth-stencil like. (excludes game textures, cubemap faces, most 3D texture LUT, texture atlas) // Detect if the texture is possibly square. Widths may be aligned, so to remove the uncertainty we align both the width and height. - int widthAlignment = (info.IsLinear ? Constants.StrideAlignment : Constants.GobAlignment) / info.FormatInfo.BytesPerPixel; - bool possiblySquare = BitUtils.AlignUp(info.Width, widthAlignment) == BitUtils.AlignUp(info.Height, widthAlignment); if (possiblySquare) @@ -132,11 +138,17 @@ namespace Ryujinx.Graphics.Gpu.Image } } - int aspect = (int)Math.Round((info.Width / (float)info.Height) * 9); - if (aspect == 16 && info.Height < 360) + if (info.Height < 360) { - // Targets that are roughly 16:9 can only be rescaled if they're equal to or above 360p. (excludes blur and bloom textures) - return false; + int aspectWidth = (int)MathF.Ceiling((info.Height / 9f) * 16f); + int aspectMaxWidth = BitUtils.AlignUp(aspectWidth, widthAlignment); + int aspectMinWidth = BitUtils.AlignDown(aspectWidth, widthAlignment); + + if (info.Width >= aspectMinWidth && info.Width <= aspectMaxWidth && info.Height < 360) + { + // Targets that are roughly 16:9 can only be rescaled if they're equal to or above 360p. (excludes blur and bloom textures) + return false; + } } return true; @@ -354,13 +366,7 @@ namespace Ryujinx.Graphics.Gpu.Image { bool isSamplerTexture = (flags & TextureSearchFlags.ForSampler) != 0; - bool isScalable = IsUpscaleCompatible(info); - - TextureScaleMode scaleMode = TextureScaleMode.Blacklisted; - if (isScalable) - { - scaleMode = (flags & TextureSearchFlags.WithUpscale) != 0 ? TextureScaleMode.Scaled : TextureScaleMode.Eligible; - } + TextureScaleMode scaleMode = IsUpscaleCompatible(info, (flags & TextureSearchFlags.WithUpscale) != 0); ulong address; diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index 157b7c17e..4db6532b8 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -140,6 +140,16 @@ namespace Ryujinx.Graphics.Gpu.Image _gpBindingsManager.SetTexturePool(gpuVa, maximumId); } + /// + /// Check if a texture's scale must be updated to match the configured resolution scale. + /// + /// The texture to check + /// True if the scale needs updating, false if the scale is up to date + private bool ScaleNeedsUpdated(Texture texture) + { + return texture != null && !(texture.ScaleMode == TextureScaleMode.Blacklisted || texture.ScaleMode == TextureScaleMode.Undesired) && texture.ScaleFactor != GraphicsConfig.ResScale; + } + /// /// Sets the render target color buffer. /// @@ -164,7 +174,7 @@ namespace Ryujinx.Graphics.Gpu.Image _rtColors[index] = color; } - return changesScale || (hasValue && color.ScaleMode != TextureScaleMode.Blacklisted && color.ScaleFactor != GraphicsConfig.ResScale); + return changesScale || ScaleNeedsUpdated(color); } /// @@ -190,7 +200,7 @@ namespace Ryujinx.Graphics.Gpu.Image _rtDepthStencil = depthStencil; } - return changesScale || (hasValue && depthStencil.ScaleMode != TextureScaleMode.Blacklisted && depthStencil.ScaleFactor != GraphicsConfig.ResScale); + return changesScale || ScaleNeedsUpdated(depthStencil); } /// @@ -214,6 +224,7 @@ namespace Ryujinx.Graphics.Gpu.Image bool mismatch = false; bool blacklisted = false; bool hasUpscaled = false; + bool hasUndesired = false; float targetScale = GraphicsConfig.ResScale; void ConsiderTarget(Texture target) @@ -230,9 +241,13 @@ namespace Ryujinx.Graphics.Gpu.Image case TextureScaleMode.Eligible: mismatch = true; // We must make a decision. break; + case TextureScaleMode.Undesired: + hasUndesired = true; + mismatch |= scale != 1f || hasUpscaled; // If another target is upscaled, scale this one up too. + break; case TextureScaleMode.Scaled: hasUpscaled = true; - mismatch |= scale != targetScale; // If the target scale has changed, reset the scale for all targets. + mismatch |= hasUndesired || scale != targetScale; // If the target scale has changed, reset the scale for all targets. break; } } @@ -254,7 +269,7 @@ namespace Ryujinx.Graphics.Gpu.Image mismatch |= blacklisted && hasUpscaled; - if (blacklisted) + if (blacklisted || (hasUndesired && !hasUpscaled)) { targetScale = 1f; } diff --git a/Ryujinx.Graphics.Gpu/Image/TextureScaleMode.cs b/Ryujinx.Graphics.Gpu/Image/TextureScaleMode.cs index 2c9e431dc..b937f5778 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureScaleMode.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureScaleMode.cs @@ -4,11 +4,13 @@ /// The scale mode for a given texture. /// Blacklisted textures cannot be scaled, Eligible textures have not been scaled yet, /// and Scaled textures have been scaled already. + /// Undesired textures will stay at 1x until a situation where they must match a scaled texture. /// enum TextureScaleMode { Eligible = 0, Scaled = 1, - Blacklisted = 2 + Blacklisted = 2, + Undesired = 3 } }