FormatCapabilities.cs
1 using Ryujinx.Common.Logging; 2 using Ryujinx.Graphics.GAL; 3 using Silk.NET.Vulkan; 4 using System; 5 using Format = Ryujinx.Graphics.GAL.Format; 6 using VkFormat = Silk.NET.Vulkan.Format; 7 8 namespace Ryujinx.Graphics.Vulkan 9 { 10 class FormatCapabilities 11 { 12 private static readonly GAL.Format[] _scaledFormats = { 13 GAL.Format.R8Uscaled, 14 GAL.Format.R8Sscaled, 15 GAL.Format.R16Uscaled, 16 GAL.Format.R16Sscaled, 17 GAL.Format.R8G8Uscaled, 18 GAL.Format.R8G8Sscaled, 19 GAL.Format.R16G16Uscaled, 20 GAL.Format.R16G16Sscaled, 21 GAL.Format.R8G8B8Uscaled, 22 GAL.Format.R8G8B8Sscaled, 23 GAL.Format.R16G16B16Uscaled, 24 GAL.Format.R16G16B16Sscaled, 25 GAL.Format.R8G8B8A8Uscaled, 26 GAL.Format.R8G8B8A8Sscaled, 27 GAL.Format.R16G16B16A16Uscaled, 28 GAL.Format.R16G16B16A16Sscaled, 29 GAL.Format.R10G10B10A2Uscaled, 30 GAL.Format.R10G10B10A2Sscaled, 31 }; 32 33 private static readonly GAL.Format[] _intFormats = { 34 GAL.Format.R8Uint, 35 GAL.Format.R8Sint, 36 GAL.Format.R16Uint, 37 GAL.Format.R16Sint, 38 GAL.Format.R8G8Uint, 39 GAL.Format.R8G8Sint, 40 GAL.Format.R16G16Uint, 41 GAL.Format.R16G16Sint, 42 GAL.Format.R8G8B8Uint, 43 GAL.Format.R8G8B8Sint, 44 GAL.Format.R16G16B16Uint, 45 GAL.Format.R16G16B16Sint, 46 GAL.Format.R8G8B8A8Uint, 47 GAL.Format.R8G8B8A8Sint, 48 GAL.Format.R16G16B16A16Uint, 49 GAL.Format.R16G16B16A16Sint, 50 GAL.Format.R10G10B10A2Uint, 51 GAL.Format.R10G10B10A2Sint, 52 }; 53 54 private readonly FormatFeatureFlags[] _bufferTable; 55 private readonly FormatFeatureFlags[] _optimalTable; 56 57 private readonly Vk _api; 58 private readonly PhysicalDevice _physicalDevice; 59 60 public FormatCapabilities(Vk api, PhysicalDevice physicalDevice) 61 { 62 _api = api; 63 _physicalDevice = physicalDevice; 64 65 int totalFormats = Enum.GetNames(typeof(Format)).Length; 66 67 _bufferTable = new FormatFeatureFlags[totalFormats]; 68 _optimalTable = new FormatFeatureFlags[totalFormats]; 69 } 70 71 public bool BufferFormatsSupport(FormatFeatureFlags flags, params Format[] formats) 72 { 73 foreach (Format format in formats) 74 { 75 if (!BufferFormatSupports(flags, format)) 76 { 77 return false; 78 } 79 } 80 81 return true; 82 } 83 84 public bool OptimalFormatsSupport(FormatFeatureFlags flags, params Format[] formats) 85 { 86 foreach (Format format in formats) 87 { 88 if (!OptimalFormatSupports(flags, format)) 89 { 90 return false; 91 } 92 } 93 94 return true; 95 } 96 97 public bool BufferFormatSupports(FormatFeatureFlags flags, Format format) 98 { 99 var formatFeatureFlags = _bufferTable[(int)format]; 100 101 if (formatFeatureFlags == 0) 102 { 103 _api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp); 104 formatFeatureFlags = fp.BufferFeatures; 105 _bufferTable[(int)format] = formatFeatureFlags; 106 } 107 108 return (formatFeatureFlags & flags) == flags; 109 } 110 111 public bool SupportsScaledVertexFormats() 112 { 113 // We want to check is all scaled formats are supported, 114 // but if the integer variant is not supported either, 115 // then the format is likely not supported at all, 116 // we ignore formats that are entirely unsupported here. 117 118 for (int i = 0; i < _scaledFormats.Length; i++) 119 { 120 if (!BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, _scaledFormats[i]) && 121 BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, _intFormats[i])) 122 { 123 return false; 124 } 125 } 126 127 return true; 128 } 129 130 public bool BufferFormatSupports(FormatFeatureFlags flags, VkFormat format) 131 { 132 _api.GetPhysicalDeviceFormatProperties(_physicalDevice, format, out var fp); 133 134 return (fp.BufferFeatures & flags) == flags; 135 } 136 137 public bool OptimalFormatSupports(FormatFeatureFlags flags, Format format) 138 { 139 var formatFeatureFlags = _optimalTable[(int)format]; 140 141 if (formatFeatureFlags == 0) 142 { 143 _api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp); 144 formatFeatureFlags = fp.OptimalTilingFeatures; 145 _optimalTable[(int)format] = formatFeatureFlags; 146 } 147 148 return (formatFeatureFlags & flags) == flags; 149 } 150 151 public VkFormat ConvertToVkFormat(Format srcFormat) 152 { 153 var format = FormatTable.GetFormat(srcFormat); 154 155 var requiredFeatures = FormatFeatureFlags.SampledImageBit | 156 FormatFeatureFlags.TransferSrcBit | 157 FormatFeatureFlags.TransferDstBit; 158 159 if (srcFormat.IsDepthOrStencil()) 160 { 161 requiredFeatures |= FormatFeatureFlags.DepthStencilAttachmentBit; 162 } 163 else if (srcFormat.IsRtColorCompatible()) 164 { 165 requiredFeatures |= FormatFeatureFlags.ColorAttachmentBit; 166 } 167 168 if (srcFormat.IsImageCompatible()) 169 { 170 requiredFeatures |= FormatFeatureFlags.StorageImageBit; 171 } 172 173 if (!OptimalFormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported)) 174 { 175 // The format is not supported. Can we convert it to a higher precision format? 176 if (IsD24S8(srcFormat)) 177 { 178 format = VkFormat.D32SfloatS8Uint; 179 } 180 else if (srcFormat == Format.R4G4B4A4Unorm) 181 { 182 format = VkFormat.R4G4B4A4UnormPack16; 183 } 184 else 185 { 186 Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host."); 187 } 188 } 189 190 return format; 191 } 192 193 public VkFormat ConvertToVertexVkFormat(Format srcFormat) 194 { 195 var format = FormatTable.GetFormat(srcFormat); 196 197 if (!BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, srcFormat) || 198 (IsRGB16IntFloat(srcFormat) && VulkanConfiguration.ForceRGB16IntFloatUnsupported)) 199 { 200 // The format is not supported. Can we convert it to an alternative format? 201 switch (srcFormat) 202 { 203 case Format.R16G16B16Float: 204 format = VkFormat.R16G16B16A16Sfloat; 205 break; 206 case Format.R16G16B16Sint: 207 format = VkFormat.R16G16B16A16Sint; 208 break; 209 case Format.R16G16B16Uint: 210 format = VkFormat.R16G16B16A16Uint; 211 break; 212 default: 213 Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host."); 214 break; 215 } 216 } 217 218 return format; 219 } 220 221 public static bool IsD24S8(Format format) 222 { 223 return format == Format.D24UnormS8Uint || format == Format.S8UintD24Unorm || format == Format.X8UintD24Unorm; 224 } 225 226 private static bool IsRGB16IntFloat(Format format) 227 { 228 return format == Format.R16G16B16Float || 229 format == Format.R16G16B16Sint || 230 format == Format.R16G16B16Uint; 231 } 232 } 233 }