FormatCapabilities.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.Graphics.GAL;
  3. using Silk.NET.Vulkan;
  4. using System;
  5. using VkFormat = Silk.NET.Vulkan.Format;
  6. namespace Ryujinx.Graphics.Vulkan
  7. {
  8. class FormatCapabilities
  9. {
  10. private readonly FormatFeatureFlags[] _bufferTable;
  11. private readonly FormatFeatureFlags[] _optimalTable;
  12. private readonly Vk _api;
  13. private readonly PhysicalDevice _physicalDevice;
  14. public FormatCapabilities(Vk api, PhysicalDevice physicalDevice)
  15. {
  16. _api = api;
  17. _physicalDevice = physicalDevice;
  18. int totalFormats = Enum.GetNames(typeof(GAL.Format)).Length;
  19. _bufferTable = new FormatFeatureFlags[totalFormats];
  20. _optimalTable = new FormatFeatureFlags[totalFormats];
  21. }
  22. public bool BufferFormatsSupport(FormatFeatureFlags flags, params GAL.Format[] formats)
  23. {
  24. foreach (GAL.Format format in formats)
  25. {
  26. if (!BufferFormatSupports(flags, format))
  27. {
  28. return false;
  29. }
  30. }
  31. return true;
  32. }
  33. public bool OptimalFormatsSupport(FormatFeatureFlags flags, params GAL.Format[] formats)
  34. {
  35. foreach (GAL.Format format in formats)
  36. {
  37. if (!OptimalFormatSupports(flags, format))
  38. {
  39. return false;
  40. }
  41. }
  42. return true;
  43. }
  44. public bool BufferFormatSupports(FormatFeatureFlags flags, GAL.Format format)
  45. {
  46. var formatFeatureFlags = _bufferTable[(int)format];
  47. if (formatFeatureFlags == 0)
  48. {
  49. _api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
  50. formatFeatureFlags = fp.BufferFeatures;
  51. _bufferTable[(int)format] = formatFeatureFlags;
  52. }
  53. return (formatFeatureFlags & flags) == flags;
  54. }
  55. public bool OptimalFormatSupports(FormatFeatureFlags flags, GAL.Format format)
  56. {
  57. var formatFeatureFlags = _optimalTable[(int)format];
  58. if (formatFeatureFlags == 0)
  59. {
  60. _api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
  61. formatFeatureFlags = fp.OptimalTilingFeatures;
  62. _optimalTable[(int)format] = formatFeatureFlags;
  63. }
  64. return (formatFeatureFlags & flags) == flags;
  65. }
  66. public VkFormat ConvertToVkFormat(GAL.Format srcFormat)
  67. {
  68. var format = FormatTable.GetFormat(srcFormat);
  69. var requiredFeatures = FormatFeatureFlags.FormatFeatureSampledImageBit |
  70. FormatFeatureFlags.FormatFeatureTransferSrcBit |
  71. FormatFeatureFlags.FormatFeatureTransferDstBit;
  72. if (srcFormat.IsDepthOrStencil())
  73. {
  74. requiredFeatures |= FormatFeatureFlags.FormatFeatureDepthStencilAttachmentBit;
  75. }
  76. else if (srcFormat.IsRtColorCompatible())
  77. {
  78. requiredFeatures |= FormatFeatureFlags.FormatFeatureColorAttachmentBit;
  79. }
  80. if (srcFormat.IsImageCompatible())
  81. {
  82. requiredFeatures |= FormatFeatureFlags.FormatFeatureStorageImageBit;
  83. }
  84. if (!OptimalFormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
  85. {
  86. // The format is not supported. Can we convert it to a higher precision format?
  87. if (IsD24S8(srcFormat))
  88. {
  89. format = VkFormat.D32SfloatS8Uint;
  90. }
  91. else
  92. {
  93. Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host.");
  94. }
  95. }
  96. return format;
  97. }
  98. public VkFormat ConvertToVertexVkFormat(GAL.Format srcFormat)
  99. {
  100. var format = FormatTable.GetFormat(srcFormat);
  101. if (!BufferFormatSupports(FormatFeatureFlags.FormatFeatureVertexBufferBit, srcFormat) ||
  102. (IsRGB16IntFloat(srcFormat) && VulkanConfiguration.ForceRGB16IntFloatUnsupported))
  103. {
  104. // The format is not supported. Can we convert it to an alternative format?
  105. switch (srcFormat)
  106. {
  107. case GAL.Format.R16G16B16Float:
  108. format = VkFormat.R16G16B16A16Sfloat;
  109. break;
  110. case GAL.Format.R16G16B16Sint:
  111. format = VkFormat.R16G16B16A16Sint;
  112. break;
  113. case GAL.Format.R16G16B16Uint:
  114. format = VkFormat.R16G16B16A16Uint;
  115. break;
  116. default:
  117. Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host.");
  118. break;
  119. }
  120. }
  121. return format;
  122. }
  123. public static bool IsD24S8(GAL.Format format)
  124. {
  125. return format == GAL.Format.D24UnormS8Uint || format == GAL.Format.S8UintD24Unorm;
  126. }
  127. private static bool IsRGB16IntFloat(GAL.Format format)
  128. {
  129. return format == GAL.Format.R16G16B16Float ||
  130. format == GAL.Format.R16G16B16Sint ||
  131. format == GAL.Format.R16G16B16Uint;
  132. }
  133. }
  134. }