aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary <mary@mary.zone>2023-04-05 19:48:38 +0200
committerGitHub <noreply@github.com>2023-04-05 14:48:38 -0300
commitc95be55091eaee446e1ad51ad215b82be5866bb3 (patch)
tree874f6119c183e3fa94bc329285b6d17ddb04d6e7
parent63dedbda862533342fd8fac148f0c1d6427c9d84 (diff)
vulkan: Cleanup PhysicalDevice and Instance querying (#4632)1.1.698
* vulkan: Move most of the properties enumeration to VulkanPhysicalDevice That clean up a bit of duplicate logic. Also move to use an hashset for device extensions. * vulkan: Move instance querying to VulkanInstance Also cleanup code to use span when possible instead of unsafe pointers. * Address gdkchan's comments
-rw-r--r--Ryujinx.Graphics.Vulkan/MemoryAllocator.cs23
-rw-r--r--Ryujinx.Graphics.Vulkan/VulkanInitialization.cs216
-rw-r--r--Ryujinx.Graphics.Vulkan/VulkanInstance.cs127
-rw-r--r--Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs70
-rw-r--r--Ryujinx.Graphics.Vulkan/VulkanRenderer.cs92
5 files changed, 311 insertions, 217 deletions
diff --git a/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs b/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs
index 6a786a96..3139e209 100644
--- a/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs
+++ b/Ryujinx.Graphics.Vulkan/MemoryAllocator.cs
@@ -9,21 +9,18 @@ namespace Ryujinx.Graphics.Vulkan
private ulong MaxDeviceMemoryUsageEstimate = 16UL * 1024 * 1024 * 1024;
private readonly Vk _api;
- private readonly PhysicalDevice _physicalDevice;
+ private readonly VulkanPhysicalDevice _physicalDevice;
private readonly Device _device;
private readonly List<MemoryAllocatorBlockList> _blockLists;
private readonly int _blockAlignment;
- private readonly PhysicalDeviceMemoryProperties _physicalDeviceMemoryProperties;
- public MemoryAllocator(Vk api, PhysicalDevice physicalDevice, Device device, uint maxMemoryAllocationCount)
+ public MemoryAllocator(Vk api, VulkanPhysicalDevice physicalDevice, Device device)
{
_api = api;
_physicalDevice = physicalDevice;
_device = device;
_blockLists = new List<MemoryAllocatorBlockList>();
- _blockAlignment = (int)Math.Min(int.MaxValue, MaxDeviceMemoryUsageEstimate / (ulong)maxMemoryAllocationCount);
-
- _api.GetPhysicalDeviceMemoryProperties(_physicalDevice, out _physicalDeviceMemoryProperties);
+ _blockAlignment = (int)Math.Min(int.MaxValue, MaxDeviceMemoryUsageEstimate / (ulong)_physicalDevice.PhysicalDeviceProperties.Limits.MaxMemoryAllocationCount);
}
public MemoryAllocation AllocateDeviceMemory(
@@ -64,9 +61,9 @@ namespace Ryujinx.Graphics.Vulkan
uint memoryTypeBits,
MemoryPropertyFlags flags)
{
- for (int i = 0; i < _physicalDeviceMemoryProperties.MemoryTypeCount; i++)
+ for (int i = 0; i < _physicalDevice.PhysicalDeviceMemoryProperties.MemoryTypeCount; i++)
{
- var type = _physicalDeviceMemoryProperties.MemoryTypes[i];
+ var type = _physicalDevice.PhysicalDeviceMemoryProperties.MemoryTypes[i];
if ((memoryTypeBits & (1 << i)) != 0)
{
@@ -80,15 +77,11 @@ namespace Ryujinx.Graphics.Vulkan
return -1;
}
- public static bool IsDeviceMemoryShared(Vk api, PhysicalDevice physicalDevice)
+ public static bool IsDeviceMemoryShared(VulkanPhysicalDevice physicalDevice)
{
- // The device is regarded as having shared memory if all heaps have the device local bit.
-
- api.GetPhysicalDeviceMemoryProperties(physicalDevice, out var properties);
-
- for (int i = 0; i < properties.MemoryHeapCount; i++)
+ for (int i = 0; i < physicalDevice.PhysicalDeviceMemoryProperties.MemoryHeapCount; i++)
{
- if (!properties.MemoryHeaps[i].Flags.HasFlag(MemoryHeapFlags.DeviceLocalBit))
+ if (!physicalDevice.PhysicalDeviceMemoryProperties.MemoryHeaps[i].Flags.HasFlag(MemoryHeapFlags.DeviceLocalBit))
{
return false;
}
diff --git a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs
index f04ab5c0..4f69cb1d 100644
--- a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs
+++ b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs
@@ -47,35 +47,23 @@ namespace Ryujinx.Graphics.Vulkan
KhrSwapchain.ExtensionName
};
- internal static Instance CreateInstance(Vk api, GraphicsDebugLevel logLevel, string[] requiredExtensions)
+ internal static VulkanInstance CreateInstance(Vk api, GraphicsDebugLevel logLevel, string[] requiredExtensions)
{
var enabledLayers = new List<string>();
+ var instanceExtensions = VulkanInstance.GetInstanceExtensions(api);
+ var instanceLayers = VulkanInstance.GetInstanceLayers(api);
+
void AddAvailableLayer(string layerName)
{
- uint layerPropertiesCount;
-
- api.EnumerateInstanceLayerProperties(&layerPropertiesCount, null).ThrowOnError();
-
- LayerProperties[] layerProperties = new LayerProperties[layerPropertiesCount];
-
- fixed (LayerProperties* pLayerProperties = layerProperties)
+ if (instanceLayers.Contains(layerName))
{
- api.EnumerateInstanceLayerProperties(&layerPropertiesCount, layerProperties).ThrowOnError();
-
- for (int i = 0; i < layerPropertiesCount; i++)
- {
- string currentLayerName = Marshal.PtrToStringAnsi((IntPtr)pLayerProperties[i].LayerName);
-
- if (currentLayerName == layerName)
- {
- enabledLayers.Add(layerName);
- return;
- }
- }
+ enabledLayers.Add(layerName);
+ }
+ else
+ {
+ Logger.Warning?.Print(LogClass.Gpu, $"Missing layer {layerName}");
}
-
- Logger.Warning?.Print(LogClass.Gpu, $"Missing layer {layerName}");
}
if (logLevel != GraphicsDebugLevel.None)
@@ -85,7 +73,7 @@ namespace Ryujinx.Graphics.Vulkan
var enabledExtensions = requiredExtensions;
- if (api.IsInstanceExtensionPresent("VK_EXT_debug_utils"))
+ if (instanceExtensions.Contains("VK_EXT_debug_utils"))
{
enabledExtensions = enabledExtensions.Append(ExtDebugUtils.ExtensionName).ToArray();
}
@@ -124,7 +112,7 @@ namespace Ryujinx.Graphics.Vulkan
EnabledLayerCount = (uint)enabledLayers.Count
};
- api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
+ Result result = VulkanInstance.Create(api, ref instanceCreateInfo, out var instance);
Marshal.FreeHGlobal(appName);
@@ -138,21 +126,14 @@ namespace Ryujinx.Graphics.Vulkan
Marshal.FreeHGlobal(ppEnabledLayers[i]);
}
+ result.ThrowOnError();
+
return instance;
}
- internal static PhysicalDevice FindSuitablePhysicalDevice(Vk api, Instance instance, SurfaceKHR surface, string preferredGpuId)
+ internal static VulkanPhysicalDevice FindSuitablePhysicalDevice(Vk api, VulkanInstance instance, SurfaceKHR surface, string preferredGpuId)
{
- uint physicalDeviceCount;
-
- api.EnumeratePhysicalDevices(instance, &physicalDeviceCount, null).ThrowOnError();
-
- PhysicalDevice[] physicalDevices = new PhysicalDevice[physicalDeviceCount];
-
- fixed (PhysicalDevice* pPhysicalDevices = physicalDevices)
- {
- api.EnumeratePhysicalDevices(instance, &physicalDeviceCount, pPhysicalDevices).ThrowOnError();
- }
+ instance.EnumeratePhysicalDevices(out var physicalDevices).ThrowOnError();
// First we try to pick the the user preferred GPU.
for (int i = 0; i < physicalDevices.Length; i++)
@@ -198,76 +179,41 @@ namespace Ryujinx.Graphics.Vulkan
EnabledLayerCount = 0
};
- api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
+ Result result = VulkanInstance.Create(api, ref instanceCreateInfo, out var rawInstance);
- // We ensure that vkEnumerateInstanceVersion is present (added in 1.1).
- // If the instance doesn't support it, no device is going to be 1.1 compatible.
- if (api.GetInstanceProcAddr(instance, "vkEnumerateInstanceVersion") == IntPtr.Zero)
- {
- api.DestroyInstance(instance, null);
+ Marshal.FreeHGlobal(appName);
- return Array.Empty<DeviceInfo>();
- }
+ result.ThrowOnError();
+
+ using VulkanInstance instance = rawInstance;
// We currently assume that the instance is compatible with Vulkan 1.2
// TODO: Remove this once we relax our initialization codepaths.
- uint instanceApiVerison = 0;
- api.EnumerateInstanceVersion(ref instanceApiVerison).ThrowOnError();
-
- if (instanceApiVerison < MinimalInstanceVulkanVersion)
+ if (instance.InstanceVersion < MinimalInstanceVulkanVersion)
{
- api.DestroyInstance(instance, null);
-
return Array.Empty<DeviceInfo>();
}
- Marshal.FreeHGlobal(appName);
-
- uint physicalDeviceCount;
-
- api.EnumeratePhysicalDevices(instance, &physicalDeviceCount, null).ThrowOnError();
+ instance.EnumeratePhysicalDevices(out VulkanPhysicalDevice[] physicalDevices).ThrowOnError();
- PhysicalDevice[] physicalDevices = new PhysicalDevice[physicalDeviceCount];
+ List<DeviceInfo> deviceInfos = new List<DeviceInfo>();
- fixed (PhysicalDevice* pPhysicalDevices = physicalDevices)
- {
- api.EnumeratePhysicalDevices(instance, &physicalDeviceCount, pPhysicalDevices).ThrowOnError();
- }
-
- DeviceInfo[] devices = new DeviceInfo[physicalDevices.Length];
-
- for (int i = 0; i < physicalDevices.Length; i++)
+ foreach (VulkanPhysicalDevice physicalDevice in physicalDevices)
{
- var physicalDevice = physicalDevices[i];
- api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
-
- if (properties.ApiVersion < MinimalVulkanVersion)
+ if (physicalDevice.PhysicalDeviceProperties.ApiVersion < MinimalVulkanVersion)
{
continue;
}
- devices[i] = new DeviceInfo(
- StringFromIdPair(properties.VendorID, properties.DeviceID),
- VendorUtils.GetNameFromId(properties.VendorID),
- Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName),
- properties.DeviceType == PhysicalDeviceType.DiscreteGpu);
+ deviceInfos.Add(physicalDevice.ToDeviceInfo());
}
- api.DestroyInstance(instance, null);
-
- return devices;
+ return deviceInfos.ToArray();
}
- public static string StringFromIdPair(uint vendorId, uint deviceId)
+ private static bool IsPreferredAndSuitableDevice(Vk api, VulkanPhysicalDevice physicalDevice, SurfaceKHR surface, string preferredGpuId)
{
- return $"0x{vendorId:X}_0x{deviceId:X}";
- }
-
- private static bool IsPreferredAndSuitableDevice(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, string preferredGpuId)
- {
- api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
-
- if (StringFromIdPair(properties.VendorID, properties.DeviceID) != preferredGpuId)
+ if (physicalDevice.Id != preferredGpuId)
{
return false;
}
@@ -275,68 +221,47 @@ namespace Ryujinx.Graphics.Vulkan
return IsSuitableDevice(api, physicalDevice, surface);
}
- private static bool IsSuitableDevice(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface)
+ private static bool IsSuitableDevice(Vk api, VulkanPhysicalDevice physicalDevice, SurfaceKHR surface)
{
int extensionMatches = 0;
- uint propertiesCount;
-
- api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, null).ThrowOnError();
- ExtensionProperties[] extensionProperties = new ExtensionProperties[propertiesCount];
-
- fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
+ foreach (string requiredExtension in _requiredExtensions)
{
- api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, pExtensionProperties).ThrowOnError();
-
- for (int i = 0; i < propertiesCount; i++)
+ if (physicalDevice.IsDeviceExtensionPresent(requiredExtension))
{
- string extensionName = Marshal.PtrToStringAnsi((IntPtr)pExtensionProperties[i].ExtensionName);
-
- if (_requiredExtensions.Contains(extensionName))
- {
- extensionMatches++;
- }
+ extensionMatches++;
}
}
return extensionMatches == _requiredExtensions.Length && FindSuitableQueueFamily(api, physicalDevice, surface, out _) != InvalidIndex;
}
- internal static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
+ internal static uint FindSuitableQueueFamily(Vk api, VulkanPhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
{
const QueueFlags RequiredFlags = QueueFlags.GraphicsBit | QueueFlags.ComputeBit;
var khrSurface = new KhrSurface(api.Context);
- uint propertiesCount;
-
- api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, null);
-
- QueueFamilyProperties[] properties = new QueueFamilyProperties[propertiesCount];
-
- fixed (QueueFamilyProperties* pProperties = properties)
+ for (uint index = 0; index < physicalDevice.QueueFamilyProperties.Length; index++)
{
- api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, pProperties);
- }
+ ref QueueFamilyProperties property = ref physicalDevice.QueueFamilyProperties[index];
- for (uint index = 0; index < propertiesCount; index++)
- {
- var queueFlags = properties[index].QueueFlags;
-
- khrSurface.GetPhysicalDeviceSurfaceSupport(physicalDevice, index, surface, out var surfaceSupported).ThrowOnError();
+ khrSurface.GetPhysicalDeviceSurfaceSupport(physicalDevice.PhysicalDevice, index, surface, out var surfaceSupported).ThrowOnError();
- if (queueFlags.HasFlag(RequiredFlags) && surfaceSupported)
+ if (property.QueueFlags.HasFlag(RequiredFlags) && surfaceSupported)
{
- queueCount = properties[index].QueueCount;
+ queueCount = property.QueueCount;
+
return index;
}
}
queueCount = 0;
+
return InvalidIndex;
}
- public static Device CreateDevice(Vk api, PhysicalDevice physicalDevice, uint queueFamilyIndex, string[] supportedExtensions, uint queueCount)
+ internal static Device CreateDevice(Vk api, VulkanPhysicalDevice physicalDevice, uint queueFamilyIndex, uint queueCount)
{
if (queueCount > QueuesCount)
{
@@ -358,8 +283,7 @@ namespace Ryujinx.Graphics.Vulkan
PQueuePriorities = queuePriorities
};
- api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
- bool useRobustBufferAccess = VendorUtils.FromId(properties.VendorID) == Vendor.Nvidia;
+ bool useRobustBufferAccess = VendorUtils.FromId(physicalDevice.PhysicalDeviceProperties.VendorID) == Vendor.Nvidia;
PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
{
@@ -380,7 +304,7 @@ namespace Ryujinx.Graphics.Vulkan
PNext = features2.PNext
};
- if (supportedExtensions.Contains("VK_EXT_custom_border_color"))
+ if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color"))
{
features2.PNext = &supportedFeaturesCustomBorderColor;
}
@@ -391,7 +315,7 @@ namespace Ryujinx.Graphics.Vulkan
PNext = features2.PNext
};
- if (supportedExtensions.Contains("VK_EXT_primitive_topology_list_restart"))
+ if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_primitive_topology_list_restart"))
{
features2.PNext = &supportedFeaturesPrimitiveTopologyListRestart;
}
@@ -402,7 +326,7 @@ namespace Ryujinx.Graphics.Vulkan
PNext = features2.PNext
};
- if (supportedExtensions.Contains(ExtTransformFeedback.ExtensionName))
+ if (physicalDevice.IsDeviceExtensionPresent(ExtTransformFeedback.ExtensionName))
{
features2.PNext = &supportedFeaturesTransformFeedback;
}
@@ -412,14 +336,14 @@ namespace Ryujinx.Graphics.Vulkan
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt
};
- if (supportedExtensions.Contains("VK_EXT_robustness2"))
+ if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
{
supportedFeaturesRobustness2.PNext = features2.PNext;
features2.PNext = &supportedFeaturesRobustness2;
}
- api.GetPhysicalDeviceFeatures2(physicalDevice, &features2);
+ api.GetPhysicalDeviceFeatures2(physicalDevice.PhysicalDevice, &features2);
var supportedFeatures = features2.Features;
@@ -452,7 +376,7 @@ namespace Ryujinx.Graphics.Vulkan
PhysicalDeviceTransformFeedbackFeaturesEXT featuresTransformFeedback;
- if (supportedExtensions.Contains(ExtTransformFeedback.ExtensionName))
+ if (physicalDevice.IsDeviceExtensionPresent(ExtTransformFeedback.ExtensionName))
{
featuresTransformFeedback = new PhysicalDeviceTransformFeedbackFeaturesEXT()
{
@@ -466,7 +390,7 @@ namespace Ryujinx.Graphics.Vulkan
PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT featuresPrimitiveTopologyListRestart;
- if (supportedExtensions.Contains("VK_EXT_primitive_topology_list_restart"))
+ if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_primitive_topology_list_restart"))
{
featuresPrimitiveTopologyListRestart = new PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT()
{
@@ -481,7 +405,7 @@ namespace Ryujinx.Graphics.Vulkan
PhysicalDeviceRobustness2FeaturesEXT featuresRobustness2;
- if (supportedExtensions.Contains("VK_EXT_robustness2"))
+ if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
{
featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT()
{
@@ -497,7 +421,7 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.PhysicalDeviceExtendedDynamicStateFeaturesExt,
PNext = pExtendedFeatures,
- ExtendedDynamicState = supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName)
+ ExtendedDynamicState = physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName)
};
pExtendedFeatures = &featuresExtendedDynamicState;
@@ -515,16 +439,16 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.PhysicalDeviceVulkan12Features,
PNext = pExtendedFeatures,
- DescriptorIndexing = supportedExtensions.Contains("VK_EXT_descriptor_indexing"),
- DrawIndirectCount = supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName),
- UniformBufferStandardLayout = supportedExtensions.Contains("VK_KHR_uniform_buffer_standard_layout")
+ DescriptorIndexing = physicalDevice.IsDeviceExtensionPresent("VK_EXT_descriptor_indexing"),
+ DrawIndirectCount = physicalDevice.IsDeviceExtensionPresent(KhrDrawIndirectCount.ExtensionName),
+ UniformBufferStandardLayout = physicalDevice.IsDeviceExtensionPresent("VK_KHR_uniform_buffer_standard_layout")
};
pExtendedFeatures = &featuresVk12;
PhysicalDeviceIndexTypeUint8FeaturesEXT featuresIndexU8;
- if (supportedExtensions.Contains("VK_EXT_index_type_uint8"))
+ if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"))
{
featuresIndexU8 = new PhysicalDeviceIndexTypeUint8FeaturesEXT()
{
@@ -538,7 +462,7 @@ namespace Ryujinx.Graphics.Vulkan
PhysicalDeviceFragmentShaderInterlockFeaturesEXT featuresFragmentShaderInterlock;
- if (supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"))
+ if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_fragment_shader_interlock"))
{
featuresFragmentShaderInterlock = new PhysicalDeviceFragmentShaderInterlockFeaturesEXT()
{
@@ -552,7 +476,7 @@ namespace Ryujinx.Graphics.Vulkan
PhysicalDeviceSubgroupSizeControlFeaturesEXT featuresSubgroupSizeControl;
- if (supportedExtensions.Contains("VK_EXT_subgroup_size_control"))
+ if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_subgroup_size_control"))
{
featuresSubgroupSizeControl = new PhysicalDeviceSubgroupSizeControlFeaturesEXT()
{
@@ -566,7 +490,7 @@ namespace Ryujinx.Graphics.Vulkan
PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColor;
- if (supportedExtensions.Contains("VK_EXT_custom_border_color") &&
+ if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color") &&
supportedFeaturesCustomBorderColor.CustomBorderColors &&
supportedFeaturesCustomBorderColor.CustomBorderColorWithoutFormat)
{
@@ -581,7 +505,7 @@ namespace Ryujinx.Graphics.Vulkan
pExtendedFeatures = &featuresCustomBorderColor;
}
- var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(supportedExtensions)).ToArray();
+ var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
@@ -601,7 +525,7 @@ namespace Ryujinx.Graphics.Vulkan
PEnabledFeatures = &features
};
- api.CreateDevice(physicalDevice, in deviceCreateInfo, null, out var device).ThrowOnError();
+ api.CreateDevice(physicalDevice.PhysicalDevice, in deviceCreateInfo, null, out var device).ThrowOnError();
for (int i = 0; i < enabledExtensions.Length; i++)
{
@@ -610,21 +534,5 @@ namespace Ryujinx.Graphics.Vulkan
return device;
}
-
- public static string[] GetSupportedExtensions(Vk api, PhysicalDevice physicalDevice)
- {
- uint propertiesCount;
-
- api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, null).ThrowOnError();
-
- ExtensionProperties[] extensionProperties = new ExtensionProperties[propertiesCount];
-
- fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
- {
- api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, pExtensionProperties).ThrowOnError();
- }
-
- return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToArray();
- }
}
}
diff --git a/Ryujinx.Graphics.Vulkan/VulkanInstance.cs b/Ryujinx.Graphics.Vulkan/VulkanInstance.cs
new file mode 100644
index 00000000..843d3412
--- /dev/null
+++ b/Ryujinx.Graphics.Vulkan/VulkanInstance.cs
@@ -0,0 +1,127 @@
+using Ryujinx.Common.Utilities;
+using Silk.NET.Core;
+using Silk.NET.Vulkan;
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Graphics.Vulkan
+{
+ class VulkanInstance : IDisposable
+ {
+ private readonly Vk _api;
+ public readonly Instance Instance;
+ public readonly Version32 InstanceVersion;
+
+ private bool _disposed;
+
+ private VulkanInstance(Vk api, Instance instance)
+ {
+ _api = api;
+ Instance = instance;
+
+ if (api.GetInstanceProcAddr(instance, "vkEnumerateInstanceVersion") == IntPtr.Zero)
+ {
+ InstanceVersion = Vk.Version10;
+ }
+ else
+ {
+ uint rawInstanceVersion = 0;
+
+ if (api.EnumerateInstanceVersion(ref rawInstanceVersion) != Result.Success)
+ {
+ rawInstanceVersion = Vk.Version11.Value;
+ }
+
+ InstanceVersion = (Version32)rawInstanceVersion;
+ }
+ }
+
+ public static Result Create(Vk api, ref InstanceCreateInfo createInfo, out VulkanInstance instance)
+ {
+ instance = null;
+
+ Instance rawInstance = default;
+
+ Result result = api.CreateInstance(SpanHelpers.AsReadOnlySpan(ref createInfo), ReadOnlySpan<AllocationCallbacks>.Empty, SpanHelpers.AsSpan(ref rawInstance));
+
+ if (result == Result.Success)
+ {
+ instance = new VulkanInstance(api, rawInstance);
+ }
+
+ return result;
+ }
+
+ public Result EnumeratePhysicalDevices(out VulkanPhysicalDevice[] physicalDevices)
+ {
+ physicalDevices = null;
+
+ uint physicalDeviceCount = 0;
+
+ Result result = _api.EnumeratePhysicalDevices(Instance, SpanHelpers.AsSpan(ref physicalDeviceCount), Span<PhysicalDevice>.Empty);
+
+ if (result != Result.Success)
+ {
+ return result;
+ }
+
+ PhysicalDevice[] rawPhysicalDevices = new PhysicalDevice[physicalDeviceCount];
+
+ result = _api.EnumeratePhysicalDevices(Instance, SpanHelpers.AsSpan(ref physicalDeviceCount), rawPhysicalDevices);
+
+ if (result != Result.Success)
+ {
+ return result;
+ }
+
+ physicalDevices = rawPhysicalDevices.Select(x => new VulkanPhysicalDevice(_api, x)).ToArray();
+
+ return Result.Success;
+ }
+
+ public static IReadOnlySet<string> GetInstanceExtensions(Vk api)
+ {
+ uint propertiesCount = 0;
+
+ api.EnumerateInstanceExtensionProperties(ReadOnlySpan<byte>.Empty, SpanHelpers.AsSpan(ref propertiesCount), Span<ExtensionProperties>.Empty).ThrowOnError();
+
+ ExtensionProperties[] extensionProperties = new ExtensionProperties[propertiesCount];
+
+ api.EnumerateInstanceExtensionProperties(ReadOnlySpan<byte>.Empty, SpanHelpers.AsSpan(ref propertiesCount), extensionProperties).ThrowOnError();
+
+ unsafe
+ {
+ return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToImmutableHashSet();
+ }
+ }
+
+ public static IReadOnlySet<string> GetInstanceLayers(Vk api)
+ {
+ uint propertiesCount = 0;
+
+ api.EnumerateInstanceLayerProperties(SpanHelpers.AsSpan(ref propertiesCount), Span<LayerProperties>.Empty).ThrowOnError();
+
+ LayerProperties[] layerProperties = new LayerProperties[propertiesCount];
+
+ api.EnumerateInstanceLayerProperties(SpanHelpers.AsSpan(ref propertiesCount), layerProperties).ThrowOnError();
+
+ unsafe
+ {
+ return layerProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.LayerName)).ToImmutableHashSet();
+ }
+ }
+
+ public void Dispose()
+ {
+ if (!_disposed)
+ {
+ _api.DestroyInstance(Instance, ReadOnlySpan<AllocationCallbacks>.Empty);
+
+ _disposed = true;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs b/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs
new file mode 100644
index 00000000..547f3654
--- /dev/null
+++ b/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs
@@ -0,0 +1,70 @@
+using Ryujinx.Common.Utilities;
+using Ryujinx.Graphics.GAL;
+using Silk.NET.Vulkan;
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Graphics.Vulkan
+{
+ readonly struct VulkanPhysicalDevice
+ {
+ public readonly PhysicalDevice PhysicalDevice;
+ public readonly PhysicalDeviceFeatures PhysicalDeviceFeatures;
+ public readonly PhysicalDeviceProperties PhysicalDeviceProperties;
+ public readonly PhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties;
+ public readonly QueueFamilyProperties[] QueueFamilyProperties;
+ public readonly string DeviceName;
+ public readonly IReadOnlySet<string> DeviceExtensions;
+
+ public VulkanPhysicalDevice(Vk api, PhysicalDevice physicalDevice)
+ {
+ PhysicalDevice = physicalDevice;
+ PhysicalDeviceFeatures = api.GetPhysicalDeviceFeature(PhysicalDevice);
+
+ api.GetPhysicalDeviceProperties(PhysicalDevice, out var physicalDeviceProperties);
+ PhysicalDeviceProperties = physicalDeviceProperties;
+
+ api.GetPhysicalDeviceMemoryProperties(PhysicalDevice, out PhysicalDeviceMemoryProperties);
+
+ unsafe
+ {
+ DeviceName = Marshal.PtrToStringAnsi((IntPtr)physicalDeviceProperties.DeviceName);
+ }
+
+ uint propertiesCount = 0;
+
+ api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, SpanHelpers.AsSpan(ref propertiesCount), Span<QueueFamilyProperties>.Empty);
+
+ QueueFamilyProperties = new QueueFamilyProperties[propertiesCount];
+
+ api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, SpanHelpers.AsSpan(ref propertiesCount), QueueFamilyProperties);
+
+ api.EnumerateDeviceExtensionProperties(PhysicalDevice, Span<byte>.Empty, SpanHelpers.AsSpan(ref propertiesCount), Span<ExtensionProperties>.Empty).ThrowOnError();
+
+ ExtensionProperties[] extensionProperties = new ExtensionProperties[propertiesCount];
+
+ api.EnumerateDeviceExtensionProperties(PhysicalDevice, Span<byte>.Empty, SpanHelpers.AsSpan(ref propertiesCount), extensionProperties).ThrowOnError();
+
+ unsafe
+ {
+ DeviceExtensions = extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToImmutableHashSet();
+ }
+ }
+
+ public string Id => $"0x{PhysicalDeviceProperties.VendorID:X}_0x{PhysicalDeviceProperties.DeviceID:X}";
+
+ public bool IsDeviceExtensionPresent(string extension) => DeviceExtensions.Contains(extension);
+
+ public DeviceInfo ToDeviceInfo()
+ {
+ return new DeviceInfo(
+ Id,
+ VendorUtils.GetNameFromId(PhysicalDeviceProperties.VendorID),
+ DeviceName,
+ PhysicalDeviceProperties.DeviceType == PhysicalDeviceType.DiscreteGpu);
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
index 81dec12e..193cdce3 100644
--- a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
+++ b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
@@ -17,9 +17,9 @@ namespace Ryujinx.Graphics.Vulkan
{
public sealed class VulkanRenderer : IRenderer
{
- private Instance _instance;
+ private VulkanInstance _instance;
private SurfaceKHR _surface;
- private PhysicalDevice _physicalDevice;
+ private VulkanPhysicalDevice _physicalDevice;
private Device _device;
private WindowBase _window;
@@ -106,33 +106,31 @@ namespace Ryujinx.Graphics.Vulkan
}
}
- private unsafe void LoadFeatures(string[] supportedExtensions, uint maxQueueCount, uint queueFamilyIndex)
+ private unsafe void LoadFeatures(uint maxQueueCount, uint queueFamilyIndex)
{
- FormatCapabilities = new FormatCapabilities(Api, _physicalDevice);
+ FormatCapabilities = new FormatCapabilities(Api, _physicalDevice.PhysicalDevice);
- var supportedFeatures = Api.GetPhysicalDeviceFeature(_physicalDevice);
-
- if (Api.TryGetDeviceExtension(_instance, _device, out ExtConditionalRendering conditionalRenderingApi))
+ if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtConditionalRendering conditionalRenderingApi))
{
ConditionalRenderingApi = conditionalRenderingApi;
}
- if (Api.TryGetDeviceExtension(_instance, _device, out ExtExtendedDynamicState extendedDynamicStateApi))
+ if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExtendedDynamicState extendedDynamicStateApi))
{
ExtendedDynamicStateApi = extendedDynamicStateApi;
}
- if (Api.TryGetDeviceExtension(_instance, _device, out KhrPushDescriptor pushDescriptorApi))
+ if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrPushDescriptor pushDescriptorApi))
{
PushDescriptorApi = pushDescriptorApi;
}
- if (Api.TryGetDeviceExtension(_instance, _device, out ExtTransformFeedback transformFeedbackApi))
+ if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtTransformFeedback transformFeedbackApi))
{
TransformFeedbackApi = transformFeedbackApi;
}
- if (Api.TryGetDeviceExtension(_instance, _device, out KhrDrawIndirectCount drawIndirectCountApi))
+ if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrDrawIndirectCount drawIndirectCountApi))
{
DrawIndirectCountApi = drawIndirectCountApi;
}
@@ -154,7 +152,7 @@ namespace Ryujinx.Graphics.Vulkan
SType = StructureType.PhysicalDeviceBlendOperationAdvancedPropertiesExt
};
- bool supportsBlendOperationAdvanced = supportedExtensions.Contains("VK_EXT_blend_operation_advanced");
+ bool supportsBlendOperationAdvanced = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_blend_operation_advanced");
if (supportsBlendOperationAdvanced)
{
@@ -167,14 +165,14 @@ namespace Ryujinx.Graphics.Vulkan
SType = StructureType.PhysicalDeviceSubgroupSizeControlPropertiesExt
};
- bool supportsSubgroupSizeControl = supportedExtensions.Contains("VK_EXT_subgroup_size_control");
+ bool supportsSubgroupSizeControl = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_subgroup_size_control");
if (supportsSubgroupSizeControl)
{
properties2.PNext = &propertiesSubgroupSizeControl;
}
- bool supportsTransformFeedback = supportedExtensions.Contains(ExtTransformFeedback.ExtensionName);
+ bool supportsTransformFeedback = _physicalDevice.IsDeviceExtensionPresent(ExtTransformFeedback.ExtensionName);
PhysicalDeviceTransformFeedbackPropertiesEXT propertiesTransformFeedback = new PhysicalDeviceTransformFeedbackPropertiesEXT()
{
@@ -222,30 +220,30 @@ namespace Ryujinx.Graphics.Vulkan
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr
};
- if (supportedExtensions.Contains("VK_EXT_primitive_topology_list_restart"))
+ if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_primitive_topology_list_restart"))
{
features2.PNext = &featuresPrimitiveTopologyListRestart;
}
- if (supportedExtensions.Contains("VK_EXT_robustness2"))
+ if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
{
featuresRobustness2.PNext = features2.PNext;
features2.PNext = &featuresRobustness2;
}
- if (supportedExtensions.Contains("VK_KHR_shader_float16_int8"))
+ if (_physicalDevice.IsDeviceExtensionPresent("VK_KHR_shader_float16_int8"))
{
featuresShaderInt8.PNext = features2.PNext;
features2.PNext = &featuresShaderInt8;
}
- if (supportedExtensions.Contains("VK_EXT_custom_border_color"))
+ if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color"))
{
featuresCustomBorderColor.PNext = features2.PNext;
features2.PNext = &featuresCustomBorderColor;
}
- bool usePortability = supportedExtensions.Contains("VK_KHR_portability_subset");
+ bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset");
if (usePortability)
{
@@ -256,8 +254,8 @@ namespace Ryujinx.Graphics.Vulkan
features2.PNext = &featuresPortabilitySubset;
}
- Api.GetPhysicalDeviceProperties2(_physicalDevice, &properties2);
- Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
+ Api.GetPhysicalDeviceProperties2(_physicalDevice.PhysicalDevice, &properties2);
+ Api.GetPhysicalDeviceFeatures2(_physicalDevice.PhysicalDevice, &features2);
var portabilityFlags = PortabilitySubsetFlags.None;
uint vertexBufferAlignment = 1;
@@ -272,7 +270,7 @@ namespace Ryujinx.Graphics.Vulkan
portabilityFlags |= featuresPortabilitySubset.SamplerMipLodBias ? 0 : PortabilitySubsetFlags.NoLodBias;
}
- bool supportsCustomBorderColor = supportedExtensions.Contains("VK_EXT_custom_border_color") &&
+ bool supportsCustomBorderColor = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color") &&
featuresCustomBorderColor.CustomBorderColors &&
featuresCustomBorderColor.CustomBorderColorWithoutFormat;
@@ -284,30 +282,30 @@ namespace Ryujinx.Graphics.Vulkan
properties.Limits.FramebufferStencilSampleCounts;
Capabilities = new HardwareCapabilities(
- supportedExtensions.Contains("VK_EXT_index_type_uint8"),
+ _physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"),
supportsCustomBorderColor,
supportsBlendOperationAdvanced,
propertiesBlendOperationAdvanced.AdvancedBlendCorrelatedOverlap,
propertiesBlendOperationAdvanced.AdvancedBlendNonPremultipliedSrcColor,
propertiesBlendOperationAdvanced.AdvancedBlendNonPremultipliedDstColor,
- supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName),
- supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"),
- supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
+ _physicalDevice.IsDeviceExtensionPresent(KhrDrawIndirectCount.ExtensionName),
+ _physicalDevice.IsDeviceExtensionPresent("VK_EXT_fragment_shader_interlock"),
+ _physicalDevice.IsDeviceExtensionPresent("VK_NV_geometry_shader_passthrough"),
supportsSubgroupSizeControl,
featuresShaderInt8.ShaderInt8,
- supportedExtensions.Contains("VK_EXT_shader_stencil_export"),
- supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
- supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName),
+ _physicalDevice.IsDeviceExtensionPresent("VK_EXT_shader_stencil_export"),
+ _physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName),
+ _physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName),
features2.Features.MultiViewport,
featuresRobustness2.NullDescriptor || IsMoltenVk,
- supportedExtensions.Contains(KhrPushDescriptor.ExtensionName),
+ _physicalDevice.IsDeviceExtensionPresent(KhrPushDescriptor.ExtensionName),
featuresPrimitiveTopologyListRestart.PrimitiveTopologyListRestart,
featuresPrimitiveTopologyListRestart.PrimitiveTopologyPatchListRestart,
supportsTransformFeedback,
propertiesTransformFeedback.TransformFeedbackQueries,
features2.Features.OcclusionQueryPrecise,
- supportedFeatures.PipelineStatisticsQuery,
- supportedFeatures.GeometryShader,
+ _physicalDevice.PhysicalDeviceFeatures.PipelineStatisticsQuery,
+ _physicalDevice.PhysicalDeviceFeatures.GeometryShader,
propertiesSubgroupSizeControl.MinSubgroupSize,
propertiesSubgroupSizeControl.MaxSubgroupSize,
propertiesSubgroupSizeControl.RequiredSubgroupSizeStages,
@@ -315,9 +313,9 @@ namespace Ryujinx.Graphics.Vulkan
portabilityFlags,
vertexBufferAlignment);
- IsSharedMemory = MemoryAllocator.IsDeviceMemoryShared(Api, _physicalDevice);
+ IsSharedMemory = MemoryAllocator.IsDeviceMemoryShared(_physicalDevice);
- MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device, properties.Limits.MaxMemoryAllocationCount);
+ MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device);
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
@@ -345,22 +343,21 @@ namespace Ryujinx.Graphics.Vulkan
Api = api;
_instance = VulkanInitialization.CreateInstance(api, logLevel, _getRequiredExtensions());
- _debugMessenger = new VulkanDebugMessenger(api, _instance, logLevel);
+ _debugMessenger = new VulkanDebugMessenger(api, _instance.Instance, logLevel);
- if (api.TryGetInstanceExtension(_instance, out KhrSurface surfaceApi))
+ if (api.TryGetInstanceExtension(_instance.Instance, out KhrSurface surfaceApi))
{
SurfaceApi = surfaceApi;
}
- _surface = _getSurface(_instance, api);
+ _surface = _getSurface(_instance.Instance, api);
_physicalDevice = VulkanInitialization.FindSuitablePhysicalDevice(api, _instance, _surface, _preferredGpuId);
var queueFamilyIndex = VulkanInitialization.FindSuitableQueueFamily(api, _physicalDevice, _surface, out uint maxQueueCount);
- var supportedExtensions = VulkanInitialization.GetSupportedExtensions(api, _physicalDevice);
- _device = VulkanInitialization.CreateDevice(api, _physicalDevice, queueFamilyIndex, supportedExtensions, maxQueueCount);
+ _device = VulkanInitialization.CreateDevice(api, _physicalDevice, queueFamilyIndex, maxQueueCount);
- if (api.TryGetDeviceExtension(_instance, _device, out KhrSwapchain swapchainApi))
+ if (api.TryGetDeviceExtension(_instance.Instance, _device, out KhrSwapchain swapchainApi))
{
SwapchainApi = swapchainApi;
}
@@ -369,9 +366,9 @@ namespace Ryujinx.Graphics.Vulkan
Queue = queue;
QueueLock = new object();
- LoadFeatures(supportedExtensions, maxQueueCount, queueFamilyIndex);
+ LoadFeatures(maxQueueCount, queueFamilyIndex);
- _window = new Window(this, _surface, _physicalDevice, _device);
+ _window = new Window(this, _surface, _physicalDevice.PhysicalDevice, _device);
_initialized = true;
}
@@ -536,10 +533,9 @@ namespace Ryujinx.Graphics.Vulkan
PNext = &featuresVk12
};
- Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
- Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
+ Api.GetPhysicalDeviceFeatures2(_physicalDevice.PhysicalDevice, &features2);
- var limits = properties.Limits;
+ var limits = _physicalDevice.PhysicalDeviceProperties.Limits;
return new Capabilities(
api: TargetApi.Vulkan,
@@ -623,7 +619,7 @@ namespace Ryujinx.Graphics.Vulkan
private unsafe void PrintGpuInformation()
{
- Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
+ var properties = _physicalDevice.PhysicalDeviceProperties;
string vendorName = VendorUtils.GetNameFromId(properties.VendorID);
@@ -807,14 +803,14 @@ namespace Ryujinx.Graphics.Vulkan
sampler.Dispose();
}
- SurfaceApi.DestroySurface(_instance, _surface, null);
+ SurfaceApi.DestroySurface(_instance.Instance, _surface, null);
Api.DestroyDevice(_device, null);
_debugMessenger.Dispose();
// Last step destroy the instance
- Api.DestroyInstance(_instance, null);
+ _instance.Dispose();
}
}
} \ No newline at end of file