SamplerDescriptor.cs
1 using Ryujinx.Graphics.GAL; 2 using System.Runtime.CompilerServices; 3 using System.Runtime.Intrinsics; 4 5 namespace Ryujinx.Graphics.Gpu.Image 6 { 7 /// <summary> 8 /// Maxwell sampler descriptor structure. 9 /// This structure defines the sampler descriptor as it is packed on the GPU sampler pool region. 10 /// </summary> 11 struct SamplerDescriptor 12 { 13 private static readonly float[] _f5ToF32ConversionLut = new float[] 14 { 15 0.0f, 16 0.055555556f, 17 0.1f, 18 0.13636364f, 19 0.16666667f, 20 0.1923077f, 21 0.21428572f, 22 0.23333333f, 23 0.25f, 24 0.2777778f, 25 0.3f, 26 0.3181818f, 27 0.33333334f, 28 0.34615386f, 29 0.35714287f, 30 0.36666667f, 31 0.375f, 32 0.3888889f, 33 0.4f, 34 0.4090909f, 35 0.41666666f, 36 0.42307693f, 37 0.42857143f, 38 0.43333334f, 39 0.4375f, 40 0.44444445f, 41 0.45f, 42 0.45454547f, 43 0.45833334f, 44 0.46153846f, 45 0.4642857f, 46 0.46666667f, 47 }; 48 49 private static readonly float[] _maxAnisotropyLut = new float[] 50 { 51 1, 2, 4, 6, 8, 10, 12, 16, 52 }; 53 54 private const float Frac8ToF32 = 1.0f / 256.0f; 55 56 #pragma warning disable CS0649 // Field is never assigned to 57 public uint Word0; 58 public uint Word1; 59 public uint Word2; 60 public uint Word3; 61 public float BorderColorR; 62 public float BorderColorG; 63 public float BorderColorB; 64 public float BorderColorA; 65 #pragma warning restore CS0649 66 67 /// <summary> 68 /// Unpacks the texture wrap mode along the X axis. 69 /// </summary> 70 /// <returns>The texture wrap mode enum</returns> 71 public readonly AddressMode UnpackAddressU() 72 { 73 return (AddressMode)(Word0 & 7); 74 } 75 76 // <summary> 77 /// Unpacks the texture wrap mode along the Y axis. 78 /// </summary> 79 /// <returns>The texture wrap mode enum</returns> 80 public readonly AddressMode UnpackAddressV() 81 { 82 return (AddressMode)((Word0 >> 3) & 7); 83 } 84 85 // <summary> 86 /// Unpacks the texture wrap mode along the Z axis. 87 /// </summary> 88 /// <returns>The texture wrap mode enum</returns> 89 public readonly AddressMode UnpackAddressP() 90 { 91 return (AddressMode)((Word0 >> 6) & 7); 92 } 93 94 /// <summary> 95 /// Unpacks the compare mode used for depth comparison on the shader, for 96 /// depth buffer texture. 97 /// This is only relevant for shaders with shadow samplers. 98 /// </summary> 99 /// <returns>The depth comparison mode enum</returns> 100 public readonly CompareMode UnpackCompareMode() 101 { 102 return (CompareMode)((Word0 >> 9) & 1); 103 } 104 105 /// <summary> 106 /// Unpacks the compare operation used for depth comparison on the shader, for 107 /// depth buffer texture. 108 /// This is only relevant for shaders with shadow samplers. 109 /// </summary> 110 /// <returns>The depth comparison operation enum</returns> 111 public readonly CompareOp UnpackCompareOp() 112 { 113 return (CompareOp)(((Word0 >> 10) & 7) + 1); 114 } 115 116 /// <summary> 117 /// Unpacks the sampler sRGB format flag. 118 /// </summary> 119 /// <returns>True if the has sampler is sRGB conversion enabled, false otherwise</returns> 120 public readonly bool UnpackSrgb() 121 { 122 return (Word0 & (1 << 13)) != 0; 123 } 124 125 /// <summary> 126 /// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering. 127 /// </summary> 128 /// <returns>The maximum anisotropy</returns> 129 public readonly float UnpackMaxAnisotropy() 130 { 131 return _maxAnisotropyLut[(Word0 >> 20) & 7]; 132 } 133 134 /// <summary> 135 /// Unpacks the texture magnification filter. 136 /// This defines the filtering used when the texture covers an area on the screen 137 /// that is larger than the texture size. 138 /// </summary> 139 /// <returns>The magnification filter</returns> 140 public readonly MagFilter UnpackMagFilter() 141 { 142 return (MagFilter)(Word1 & 3); 143 } 144 145 /// <summary> 146 /// Unpacks the texture minification filter. 147 /// This defines the filtering used when the texture covers an area on the screen 148 /// that is smaller than the texture size. 149 /// </summary> 150 /// <returns>The minification filter</returns> 151 public readonly MinFilter UnpackMinFilter() 152 { 153 SamplerMinFilter minFilter = (SamplerMinFilter)((Word1 >> 4) & 3); 154 SamplerMipFilter mipFilter = (SamplerMipFilter)((Word1 >> 6) & 3); 155 156 return ConvertFilter(minFilter, mipFilter); 157 } 158 159 /// <summary> 160 /// Converts two minification and filter enum, to a single minification enum, 161 /// including mipmap filtering information, as expected from the host API. 162 /// </summary> 163 /// <param name="minFilter">The minification filter</param> 164 /// <param name="mipFilter">The mipmap level filter</param> 165 /// <returns>The combined, host API compatible filter enum</returns> 166 private static MinFilter ConvertFilter(SamplerMinFilter minFilter, SamplerMipFilter mipFilter) 167 { 168 switch (mipFilter) 169 { 170 case SamplerMipFilter.None: 171 switch (minFilter) 172 { 173 case SamplerMinFilter.Nearest: 174 return MinFilter.Nearest; 175 case SamplerMinFilter.Linear: 176 return MinFilter.Linear; 177 } 178 break; 179 180 case SamplerMipFilter.Nearest: 181 switch (minFilter) 182 { 183 case SamplerMinFilter.Nearest: 184 return MinFilter.NearestMipmapNearest; 185 case SamplerMinFilter.Linear: 186 return MinFilter.LinearMipmapNearest; 187 } 188 break; 189 190 case SamplerMipFilter.Linear: 191 switch (minFilter) 192 { 193 case SamplerMinFilter.Nearest: 194 return MinFilter.NearestMipmapLinear; 195 case SamplerMinFilter.Linear: 196 return MinFilter.LinearMipmapLinear; 197 } 198 break; 199 } 200 201 return MinFilter.Nearest; 202 } 203 204 /// <summary> 205 /// Unpacks the seamless cubemap flag. 206 /// </summary> 207 /// <returns>The seamless cubemap flag</returns> 208 public readonly bool UnpackSeamlessCubemap() 209 { 210 return (Word1 & (1 << 9)) != 0; 211 } 212 213 /// <summary> 214 /// Unpacks the reduction filter, used with texture minification linear filtering. 215 /// This describes how the final value will be computed from neighbouring pixels. 216 /// </summary> 217 /// <returns>The reduction filter</returns> 218 public readonly ReductionFilter UnpackReductionFilter() 219 { 220 return (ReductionFilter)((Word1 >> 10) & 3); 221 } 222 223 /// <summary> 224 /// Unpacks the level-of-detail bias value. 225 /// This is a bias added to the level-of-detail value as computed by the GPU, used to select 226 /// which mipmap level to use from a given texture. 227 /// </summary> 228 /// <returns>The level-of-detail bias value</returns> 229 public readonly float UnpackMipLodBias() 230 { 231 int fixedValue = (int)(Word1 >> 12) & 0x1fff; 232 233 fixedValue = (fixedValue << 19) >> 19; 234 235 return fixedValue * Frac8ToF32; 236 } 237 238 /// <summary> 239 /// Unpacks the level-of-detail snap value. 240 /// </summary> 241 /// <returns>The level-of-detail snap value</returns> 242 public readonly float UnpackLodSnap() 243 { 244 return _f5ToF32ConversionLut[(Word1 >> 26) & 0x1f]; 245 } 246 247 /// <summary> 248 /// Unpacks the minimum level-of-detail value. 249 /// </summary> 250 /// <returns>The minimum level-of-detail value</returns> 251 public readonly float UnpackMinLod() 252 { 253 return (Word2 & 0xfff) * Frac8ToF32; 254 } 255 256 /// <summary> 257 /// Unpacks the maximum level-of-detail value. 258 /// </summary> 259 /// <returns>The maximum level-of-detail value</returns> 260 public readonly float UnpackMaxLod() 261 { 262 return ((Word2 >> 12) & 0xfff) * Frac8ToF32; 263 } 264 265 /// <summary> 266 /// Check if two descriptors are equal. 267 /// </summary> 268 /// <param name="other">The descriptor to compare against</param> 269 /// <returns>True if they are equal, false otherwise</returns> 270 public bool Equals(ref SamplerDescriptor other) 271 { 272 return Unsafe.As<SamplerDescriptor, Vector256<byte>>(ref this).Equals(Unsafe.As<SamplerDescriptor, Vector256<byte>>(ref other)); 273 } 274 } 275 }