aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/FormatCapabilities.cs')
-rw-r--r--Ryujinx.Graphics.Vulkan/FormatCapabilities.cs93
1 files changed, 93 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs b/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
new file mode 100644
index 00000000..6159f2cc
--- /dev/null
+++ b/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
@@ -0,0 +1,93 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Graphics.GAL;
+using Silk.NET.Vulkan;
+using System;
+using VkFormat = Silk.NET.Vulkan.Format;
+
+namespace Ryujinx.Graphics.Vulkan
+{
+ class FormatCapabilities
+ {
+ private readonly FormatFeatureFlags[] _table;
+
+ private readonly Vk _api;
+ private readonly PhysicalDevice _physicalDevice;
+
+ public FormatCapabilities(Vk api, PhysicalDevice physicalDevice)
+ {
+ _api = api;
+ _physicalDevice = physicalDevice;
+ _table = new FormatFeatureFlags[Enum.GetNames(typeof(GAL.Format)).Length];
+ }
+
+ public bool FormatsSupports(FormatFeatureFlags flags, params GAL.Format[] formats)
+ {
+ foreach (GAL.Format format in formats)
+ {
+ if (!FormatSupports(flags, format))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public bool FormatSupports(FormatFeatureFlags flags, GAL.Format format)
+ {
+ var formatFeatureFlags = _table[(int)format];
+
+ if (formatFeatureFlags == 0)
+ {
+ _api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
+ formatFeatureFlags = fp.OptimalTilingFeatures;
+ _table[(int)format] = formatFeatureFlags;
+ }
+
+ return (formatFeatureFlags & flags) == flags;
+ }
+
+ public VkFormat ConvertToVkFormat(GAL.Format srcFormat)
+ {
+ var format = FormatTable.GetFormat(srcFormat);
+
+ var requiredFeatures = FormatFeatureFlags.FormatFeatureSampledImageBit |
+ FormatFeatureFlags.FormatFeatureTransferSrcBit |
+ FormatFeatureFlags.FormatFeatureTransferDstBit;
+
+ if (srcFormat.IsDepthOrStencil())
+ {
+ requiredFeatures |= FormatFeatureFlags.FormatFeatureDepthStencilAttachmentBit;
+ }
+ else if (srcFormat.IsRtColorCompatible())
+ {
+ requiredFeatures |= FormatFeatureFlags.FormatFeatureColorAttachmentBit;
+ }
+
+ if (srcFormat.IsImageCompatible())
+ {
+ requiredFeatures |= FormatFeatureFlags.FormatFeatureStorageImageBit;
+ }
+
+ if (!FormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
+ {
+ // The format is not supported. Can we convert it to a higher precision format?
+ if (IsD24S8(srcFormat))
+ {
+ format = VkFormat.D32SfloatS8Uint;
+ }
+ else
+ {
+ Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host.");
+ }
+ }
+
+ return format;
+ }
+
+ public static bool IsD24S8(GAL.Format format)
+ {
+ return format == GAL.Format.D24UnormS8Uint || format == GAL.Format.S8UintD24Unorm;
+ }
+ }
+}