using Ryujinx.Graphics.GAL; using Silk.NET.Vulkan; namespace Ryujinx.Graphics.Vulkan { class SamplerHolder : ISampler { private readonly VulkanRenderer _gd; private readonly Auto _sampler; public unsafe SamplerHolder(VulkanRenderer gd, Device device, GAL.SamplerCreateInfo info) { _gd = gd; gd.Samplers.Add(this); (Filter minFilter, SamplerMipmapMode mipFilter) = EnumConversion.Convert(info.MinFilter); float minLod = info.MinLod; float maxLod = info.MaxLod; if (info.MinFilter == MinFilter.Nearest || info.MinFilter == MinFilter.Linear) { minLod = 0; maxLod = 0.25f; } var borderColor = GetConstrainedBorderColor(info.BorderColor, out var cantConstrain); var samplerCreateInfo = new Silk.NET.Vulkan.SamplerCreateInfo() { SType = StructureType.SamplerCreateInfo, MagFilter = info.MagFilter.Convert(), MinFilter = minFilter, MipmapMode = mipFilter, AddressModeU = info.AddressU.Convert(), AddressModeV = info.AddressV.Convert(), AddressModeW = info.AddressP.Convert(), MipLodBias = info.MipLodBias, AnisotropyEnable = info.MaxAnisotropy != 1f, MaxAnisotropy = info.MaxAnisotropy, CompareEnable = info.CompareMode == CompareMode.CompareRToTexture, CompareOp = info.CompareOp.Convert(), MinLod = minLod, MaxLod = maxLod, BorderColor = borderColor, UnnormalizedCoordinates = false // TODO: Use unnormalized coordinates. }; SamplerCustomBorderColorCreateInfoEXT customBorderColor; if (cantConstrain && gd.Capabilities.SupportsCustomBorderColor) { var color = new ClearColorValue( info.BorderColor.Red, info.BorderColor.Green, info.BorderColor.Blue, info.BorderColor.Alpha); customBorderColor = new SamplerCustomBorderColorCreateInfoEXT() { SType = StructureType.SamplerCustomBorderColorCreateInfoExt, CustomBorderColor = color }; samplerCreateInfo.PNext = &customBorderColor; samplerCreateInfo.BorderColor = BorderColor.FloatCustomExt; } gd.Api.CreateSampler(device, samplerCreateInfo, null, out var sampler).ThrowOnError(); _sampler = new Auto(new DisposableSampler(gd.Api, device, sampler)); } private static BorderColor GetConstrainedBorderColor(ColorF arbitraryBorderColor, out bool cantConstrain) { float r = arbitraryBorderColor.Red; float g = arbitraryBorderColor.Green; float b = arbitraryBorderColor.Blue; float a = arbitraryBorderColor.Alpha; if (r == 0f && g == 0f && b == 0f) { if (a == 1f) { cantConstrain = false; return BorderColor.FloatOpaqueBlack; } else if (a == 0f) { cantConstrain = false; return BorderColor.FloatTransparentBlack; } } else if (r == 1f && g == 1f && b == 1f && a == 1f) { cantConstrain = false; return BorderColor.FloatOpaqueWhite; } cantConstrain = true; return BorderColor.FloatOpaqueBlack; } public Auto GetSampler() { return _sampler; } public void Dispose() { if (_gd.Samplers.Remove(this)) { _sampler.Dispose(); } } } }