using Ryujinx.Graphics.GAL;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
namespace Ryujinx.Graphics.Gpu.Image
{
///
/// Maxwell sampler descriptor structure.
/// This structure defines the sampler descriptor as it is packed on the GPU sampler pool region.
///
struct SamplerDescriptor
{
private static readonly float[] _f5ToF32ConversionLut = new float[]
{
0.0f,
0.055555556f,
0.1f,
0.13636364f,
0.16666667f,
0.1923077f,
0.21428572f,
0.23333333f,
0.25f,
0.2777778f,
0.3f,
0.3181818f,
0.33333334f,
0.34615386f,
0.35714287f,
0.36666667f,
0.375f,
0.3888889f,
0.4f,
0.4090909f,
0.41666666f,
0.42307693f,
0.42857143f,
0.43333334f,
0.4375f,
0.44444445f,
0.45f,
0.45454547f,
0.45833334f,
0.46153846f,
0.4642857f,
0.46666667f,
};
private static readonly float[] _maxAnisotropyLut = new float[]
{
1, 2, 4, 6, 8, 10, 12, 16,
};
private const float Frac8ToF32 = 1.0f / 256.0f;
#pragma warning disable CS0649 // Field is never assigned to
public uint Word0;
public uint Word1;
public uint Word2;
public uint Word3;
public float BorderColorR;
public float BorderColorG;
public float BorderColorB;
public float BorderColorA;
#pragma warning restore CS0649
///
/// Unpacks the texture wrap mode along the X axis.
///
/// The texture wrap mode enum
public readonly AddressMode UnpackAddressU()
{
return (AddressMode)(Word0 & 7);
}
//
/// Unpacks the texture wrap mode along the Y axis.
///
/// The texture wrap mode enum
public readonly AddressMode UnpackAddressV()
{
return (AddressMode)((Word0 >> 3) & 7);
}
//
/// Unpacks the texture wrap mode along the Z axis.
///
/// The texture wrap mode enum
public readonly AddressMode UnpackAddressP()
{
return (AddressMode)((Word0 >> 6) & 7);
}
///
/// Unpacks the compare mode used for depth comparison on the shader, for
/// depth buffer texture.
/// This is only relevant for shaders with shadow samplers.
///
/// The depth comparison mode enum
public readonly CompareMode UnpackCompareMode()
{
return (CompareMode)((Word0 >> 9) & 1);
}
///
/// Unpacks the compare operation used for depth comparison on the shader, for
/// depth buffer texture.
/// This is only relevant for shaders with shadow samplers.
///
/// The depth comparison operation enum
public readonly CompareOp UnpackCompareOp()
{
return (CompareOp)(((Word0 >> 10) & 7) + 1);
}
///
/// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering.
///
/// The maximum anisotropy
public readonly float UnpackMaxAnisotropy()
{
return _maxAnisotropyLut[(Word0 >> 20) & 7];
}
///
/// Unpacks the texture magnification filter.
/// This defines the filtering used when the texture covers an area on the screen
/// that is larger than the texture size.
///
/// The magnification filter
public readonly MagFilter UnpackMagFilter()
{
return (MagFilter)(Word1 & 3);
}
///
/// Unpacks the texture minification filter.
/// This defines the filtering used when the texture covers an area on the screen
/// that is smaller than the texture size.
///
/// The minification filter
public readonly MinFilter UnpackMinFilter()
{
SamplerMinFilter minFilter = (SamplerMinFilter)((Word1 >> 4) & 3);
SamplerMipFilter mipFilter = (SamplerMipFilter)((Word1 >> 6) & 3);
return ConvertFilter(minFilter, mipFilter);
}
///
/// Converts two minification and filter enum, to a single minification enum,
/// including mipmap filtering information, as expected from the host API.
///
/// The minification filter
/// The mipmap level filter
/// The combined, host API compatible filter enum
private static MinFilter ConvertFilter(SamplerMinFilter minFilter, SamplerMipFilter mipFilter)
{
switch (mipFilter)
{
case SamplerMipFilter.None:
switch (minFilter)
{
case SamplerMinFilter.Nearest:
return MinFilter.Nearest;
case SamplerMinFilter.Linear:
return MinFilter.Linear;
}
break;
case SamplerMipFilter.Nearest:
switch (minFilter)
{
case SamplerMinFilter.Nearest:
return MinFilter.NearestMipmapNearest;
case SamplerMinFilter.Linear:
return MinFilter.LinearMipmapNearest;
}
break;
case SamplerMipFilter.Linear:
switch (minFilter)
{
case SamplerMinFilter.Nearest:
return MinFilter.NearestMipmapLinear;
case SamplerMinFilter.Linear:
return MinFilter.LinearMipmapLinear;
}
break;
}
return MinFilter.Nearest;
}
///
/// Unpacks the seamless cubemap flag.
///
/// The seamless cubemap flag
public readonly bool UnpackSeamlessCubemap()
{
return (Word1 & (1 << 9)) != 0;
}
///
/// Unpacks the reduction filter, used with texture minification linear filtering.
/// This describes how the final value will be computed from neighbouring pixels.
///
/// The reduction filter
public readonly ReductionFilter UnpackReductionFilter()
{
return (ReductionFilter)((Word1 >> 10) & 3);
}
///
/// Unpacks the level-of-detail bias value.
/// This is a bias added to the level-of-detail value as computed by the GPU, used to select
/// which mipmap level to use from a given texture.
///
/// The level-of-detail bias value
public readonly float UnpackMipLodBias()
{
int fixedValue = (int)(Word1 >> 12) & 0x1fff;
fixedValue = (fixedValue << 19) >> 19;
return fixedValue * Frac8ToF32;
}
///
/// Unpacks the level-of-detail snap value.
///
/// The level-of-detail snap value
public readonly float UnpackLodSnap()
{
return _f5ToF32ConversionLut[(Word1 >> 26) & 0x1f];
}
///
/// Unpacks the minimum level-of-detail value.
///
/// The minimum level-of-detail value
public readonly float UnpackMinLod()
{
return (Word2 & 0xfff) * Frac8ToF32;
}
///
/// Unpacks the maximum level-of-detail value.
///
/// The maximum level-of-detail value
public readonly float UnpackMaxLod()
{
return ((Word2 >> 12) & 0xfff) * Frac8ToF32;
}
///
/// Check if two descriptors are equal.
///
/// The descriptor to compare against
/// True if they are equal, false otherwise
public bool Equals(ref SamplerDescriptor other)
{
return Unsafe.As>(ref this).Equals(Unsafe.As>(ref other));
}
}
}