Ryujinx/Ryujinx.Graphics.Vulkan/VulkanInstance.cs
Mary c95be55091
vulkan: Cleanup PhysicalDevice and Instance querying (#4632)
* 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
2023-04-05 14:48:38 -03:00

128 lines
4.1 KiB
C#

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;
}
}
}
}