diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
index 518e71ade..8f69eaa74 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 4c05329ae..52d5ccec1 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
///
class Sampler : IDisposable
{
+ private const int MinLevelsForAnisotropic = 5;
+
///
/// Host sampler object.
///
- public ISampler HostSampler { get; }
+ private readonly ISampler _hostSampler;
+
+ ///
+ /// Host sampler object, with anisotropy forced.
+ ///
+ private readonly ISampler _anisoSampler;
///
/// 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)));
+ }
+ }
+
+ ///
+ /// Gets a host sampler for the given texture.
+ ///
+ /// Texture to be sampled
+ /// A host sampler
+ public ISampler GetHostSampler(Texture texture)
+ {
+ return _anisoSampler != null && AllowForceAnisotropy(texture) ? _anisoSampler : _hostSampler;
+ }
+
+ ///
+ /// 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.
+ ///
+ /// The texture
+ /// True if anisotropic filtering can be forced, false otherwise
+ 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);
}
///
@@ -69,7 +123,8 @@ namespace Ryujinx.Graphics.Gpu.Image
///
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 5a84bd847..e205ec487 100644
--- a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
@@ -7,6 +7,8 @@ namespace Ryujinx.Graphics.Gpu.Image
///
class SamplerPool : Pool
{
+ private float _forcedAnisotropy;
+
///
/// Constructs a new instance of the sampler pool.
///
@@ -14,7 +16,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Physical memory where the sampler descriptors are mapped
/// Address of the sampler pool in guest memory
/// Maximum sampler ID of the sampler pool (equal to maximum samplers minus one)
- 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;
+ }
///
/// 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 621dc2e74..e7561f7df 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)
{