aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2021-11-13 19:04:21 +0000
committerGitHub <noreply@github.com>2021-11-13 16:04:21 -0300
commit788aec511ffe64c9a22024d1b88334ec8e3b5ad6 (patch)
tree4d5b119b3e11c0421b76123c38ecaf9383e6ff68
parent611bec6e44effa90554c95ed1fe4dd4812893947 (diff)
Limit Custom Anisotropic Filtering to mipmapped textures with many levels (#2832)
* Limit Custom Anisotropic Filtering to only fully mipmapped textures There's a major flaw with the anisotropic filtering setting that causes @GamerzHell9137 to report graphical bugs that otherwise wouldn't be there, because he just won't set it to Auto. This should fix those issues, hopefully. These bugs are generally because anisotropic filtering is enabled on something that it shouldn't be, such as a post process filter or some data texture. This PR maintains two host samplers when custom AF is enabled, and only uses the forced AF one when the texture is 2d and fully mipmapped (goes down to 1x1). This is because game textures are the ideal target for this filtering, and they are typically fully mipmapped, unlike things like screen render targets which usually have 1 or just a few levels. This also only enables AF on mipmapped samplers where the filtering is bilinear or trilinear. This should be self explanatory. This PR also allows the changing of Anisotropic Filtering at runtime, and you can immediately see the changes. All samplers are flushed from the cache if the setting changes, causing them to be recreated with the new custom AF value. This brings it in line with our resolution scale. :relieved: * Expected minimum mip count for large textures rather than all, address feedback * Use Target rather than Info.Target * Retrigger build? * Fix rebase
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Image/Sampler.cs71
-rw-r--r--Ryujinx.Graphics.Gpu/Image/SamplerPool.cs22
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs2
4 files changed, 86 insertions, 11 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
index 518e71ad..8f69eaa7 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
@@ -373,7 +373,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_context.Renderer.Pipeline.DrawTexture(
texture?.HostTexture,
- sampler?.HostSampler,
+ sampler?.GetHostSampler(texture),
new Extents2DF(srcX0, srcY0, srcX1, srcY1),
new Extents2DF(dstX0, dstY0, dstX1, dstY1));
}
diff --git a/Ryujinx.Graphics.Gpu/Image/Sampler.cs b/Ryujinx.Graphics.Gpu/Image/Sampler.cs
index 4c05329a..52d5ccec 100644
--- a/Ryujinx.Graphics.Gpu/Image/Sampler.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Sampler.cs
@@ -1,5 +1,6 @@
using Ryujinx.Graphics.GAL;
using System;
+using System.Numerics;
namespace Ryujinx.Graphics.Gpu.Image
{
@@ -8,10 +9,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
class Sampler : IDisposable
{
+ private const int MinLevelsForAnisotropic = 5;
+
/// <summary>
/// Host sampler object.
/// </summary>
- public ISampler HostSampler { get; }
+ private readonly ISampler _hostSampler;
+
+ /// <summary>
+ /// Host sampler object, with anisotropy forced.
+ /// </summary>
+ private readonly ISampler _anisoSampler;
/// <summary>
/// Creates a new instance of the cached sampler.
@@ -42,13 +50,10 @@ namespace Ryujinx.Graphics.Gpu.Image
float maxLod = descriptor.UnpackMaxLod();
float mipLodBias = descriptor.UnpackMipLodBias();
- float maxRequestedAnisotropy = GraphicsConfig.MaxAnisotropy >= 0 && GraphicsConfig.MaxAnisotropy <= 16 ? GraphicsConfig.MaxAnisotropy : descriptor.UnpackMaxAnisotropy();
+ float maxRequestedAnisotropy = descriptor.UnpackMaxAnisotropy();
float maxSupportedAnisotropy = context.Capabilities.MaximumSupportedAnisotropy;
- if (maxRequestedAnisotropy > maxSupportedAnisotropy)
- maxRequestedAnisotropy = maxSupportedAnisotropy;
-
- HostSampler = context.Renderer.CreateSampler(new SamplerCreateInfo(
+ _hostSampler = context.Renderer.CreateSampler(new SamplerCreateInfo(
minFilter,
magFilter,
seamlessCubemap,
@@ -61,7 +66,56 @@ namespace Ryujinx.Graphics.Gpu.Image
minLod,
maxLod,
mipLodBias,
- maxRequestedAnisotropy));
+ Math.Min(maxRequestedAnisotropy, maxSupportedAnisotropy)));
+
+ if (GraphicsConfig.MaxAnisotropy >= 0 && GraphicsConfig.MaxAnisotropy <= 16 && (minFilter == MinFilter.LinearMipmapNearest || minFilter == MinFilter.LinearMipmapLinear))
+ {
+ maxRequestedAnisotropy = GraphicsConfig.MaxAnisotropy;
+
+ _anisoSampler = context.Renderer.CreateSampler(new SamplerCreateInfo(
+ minFilter,
+ magFilter,
+ seamlessCubemap,
+ addressU,
+ addressV,
+ addressP,
+ compareMode,
+ compareOp,
+ color,
+ minLod,
+ maxLod,
+ mipLodBias,
+ Math.Min(maxRequestedAnisotropy, maxSupportedAnisotropy)));
+ }
+ }
+
+ /// <summary>
+ /// Gets a host sampler for the given texture.
+ /// </summary>
+ /// <param name="texture">Texture to be sampled</param>
+ /// <returns>A host sampler</returns>
+ public ISampler GetHostSampler(Texture texture)
+ {
+ return _anisoSampler != null && AllowForceAnisotropy(texture) ? _anisoSampler : _hostSampler;
+ }
+
+ /// <summary>
+ /// Determine if the given texture can have anisotropic filtering forced.
+ /// Filtered textures that we might want to force anisotropy on should have a lot of mip levels.
+ /// </summary>
+ /// <param name="texture">The texture</param>
+ /// <returns>True if anisotropic filtering can be forced, false otherwise</returns>
+ private static bool AllowForceAnisotropy(Texture texture)
+ {
+ if (texture == null || !(texture.Target == Target.Texture2D || texture.Target == Target.Texture2DArray))
+ {
+ return false;
+ }
+
+ int maxSize = Math.Max(texture.Info.Width, texture.Info.Height);
+ int maxLevels = BitOperations.Log2((uint)maxSize) + 1;
+
+ return texture.Info.Levels >= Math.Min(MinLevelsForAnisotropic, maxLevels);
}
/// <summary>
@@ -69,7 +123,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
public void Dispose()
{
- HostSampler.Dispose();
+ _hostSampler.Dispose();
+ _anisoSampler?.Dispose();
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
index 5a84bd84..e205ec48 100644
--- a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
@@ -7,6 +7,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
class SamplerPool : Pool<Sampler, SamplerDescriptor>
{
+ private float _forcedAnisotropy;
+
/// <summary>
/// Constructs a new instance of the sampler pool.
/// </summary>
@@ -14,7 +16,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="physicalMemory">Physical memory where the sampler descriptors are mapped</param>
/// <param name="address">Address of the sampler pool in guest memory</param>
/// <param name="maximumId">Maximum sampler ID of the sampler pool (equal to maximum samplers minus one)</param>
- public SamplerPool(GpuContext context, PhysicalMemory physicalMemory, ulong address, int maximumId) : base(context, physicalMemory, address, maximumId) { }
+ public SamplerPool(GpuContext context, PhysicalMemory physicalMemory, ulong address, int maximumId) : base(context, physicalMemory, address, maximumId)
+ {
+ _forcedAnisotropy = GraphicsConfig.MaxAnisotropy;
+ }
/// <summary>
/// Gets the sampler with the given ID.
@@ -30,6 +35,21 @@ namespace Ryujinx.Graphics.Gpu.Image
if (SequenceNumber != Context.SequenceNumber)
{
+ if (_forcedAnisotropy != GraphicsConfig.MaxAnisotropy)
+ {
+ _forcedAnisotropy = GraphicsConfig.MaxAnisotropy;
+
+ for (int i = 0; i < Items.Length; i++)
+ {
+ if (Items[i] != null)
+ {
+ Items[i].Dispose();
+
+ Items[i] = null;
+ }
+ }
+ }
+
SequenceNumber = Context.SequenceNumber;
SynchronizeMemory();
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index 621dc2e7..e7561f7d 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -399,7 +399,7 @@ namespace Ryujinx.Graphics.Gpu.Image
Sampler sampler = samplerPool?.Get(samplerId);
- ISampler hostSampler = sampler?.HostSampler;
+ ISampler hostSampler = sampler?.GetHostSampler(texture);
if (_textureState[stageIndex][index].Sampler != hostSampler || _rebind)
{