using Ryujinx.Graphics.GAL; using System; using System.Numerics; namespace Ryujinx.Graphics.Gpu.Image { /// /// Cached sampler entry for sampler pools. /// class Sampler : IDisposable { private const int MinLevelsForAnisotropic = 5; /// /// Host sampler object. /// private readonly ISampler _hostSampler; /// /// Host sampler object, with anisotropy forced. /// private readonly ISampler _anisoSampler; /// /// Creates a new instance of the cached sampler. /// /// The GPU context the sampler belongs to /// The Maxwell sampler descriptor public Sampler(GpuContext context, SamplerDescriptor descriptor) { MinFilter minFilter = descriptor.UnpackMinFilter(); MagFilter magFilter = descriptor.UnpackMagFilter(); bool seamlessCubemap = descriptor.UnpackSeamlessCubemap(); AddressMode addressU = descriptor.UnpackAddressU(); AddressMode addressV = descriptor.UnpackAddressV(); AddressMode addressP = descriptor.UnpackAddressP(); CompareMode compareMode = descriptor.UnpackCompareMode(); CompareOp compareOp = descriptor.UnpackCompareOp(); ColorF color = new ColorF( descriptor.BorderColorR, descriptor.BorderColorG, descriptor.BorderColorB, descriptor.BorderColorA); float minLod = descriptor.UnpackMinLod(); float maxLod = descriptor.UnpackMaxLod(); float mipLodBias = descriptor.UnpackMipLodBias(); float maxRequestedAnisotropy = descriptor.UnpackMaxAnisotropy(); float maxSupportedAnisotropy = context.Capabilities.MaximumSupportedAnisotropy; _hostSampler = context.Renderer.CreateSampler(new SamplerCreateInfo( minFilter, magFilter, seamlessCubemap, addressU, addressV, addressP, compareMode, compareOp, color, minLod, maxLod, mipLodBias, 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); } /// /// Disposes the host sampler object. /// public void Dispose() { _hostSampler.Dispose(); _anisoSampler?.Dispose(); } } }