VulkanInstance.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using Silk.NET.Core;
  6. using Silk.NET.Vulkan;
  7. using Silk.NET.Vulkan.Extensions.EXT;
  8. namespace Ryujinx.Ava.Ui.Vulkan
  9. {
  10. public class VulkanInstance : IDisposable
  11. {
  12. private const string EngineName = "Avalonia Vulkan";
  13. private VulkanInstance(Instance apiHandle, Vk api)
  14. {
  15. InternalHandle = apiHandle;
  16. Api = api;
  17. }
  18. public IntPtr Handle => InternalHandle.Handle;
  19. internal Instance InternalHandle { get; }
  20. public Vk Api { get; }
  21. internal static IEnumerable<string> RequiredInstanceExtensions
  22. {
  23. get
  24. {
  25. yield return "VK_KHR_surface";
  26. if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  27. {
  28. yield return "VK_KHR_xlib_surface";
  29. }
  30. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  31. {
  32. yield return "VK_KHR_win32_surface";
  33. }
  34. }
  35. }
  36. public void Dispose()
  37. {
  38. Api?.DestroyInstance(InternalHandle, Span<AllocationCallbacks>.Empty);
  39. Api?.Dispose();
  40. }
  41. internal static unsafe VulkanInstance Create(VulkanOptions options)
  42. {
  43. var api = Vk.GetApi();
  44. var applicationName = Marshal.StringToHGlobalAnsi(options.ApplicationName);
  45. var engineName = Marshal.StringToHGlobalAnsi(EngineName);
  46. var enabledExtensions = new List<string>(options.InstanceExtensions);
  47. enabledExtensions.AddRange(RequiredInstanceExtensions);
  48. var applicationInfo = new ApplicationInfo
  49. {
  50. PApplicationName = (byte*)applicationName,
  51. ApiVersion = new Version32((uint)options.VulkanVersion.Major, (uint)options.VulkanVersion.Minor,
  52. (uint)options.VulkanVersion.Build),
  53. PEngineName = (byte*)engineName,
  54. EngineVersion = new Version32(1, 0, 0),
  55. ApplicationVersion = new Version32(1, 0, 0)
  56. };
  57. var enabledLayers = new HashSet<string>();
  58. if (options.UseDebug)
  59. {
  60. enabledExtensions.Add(ExtDebugUtils.ExtensionName);
  61. enabledExtensions.Add(ExtDebugReport.ExtensionName);
  62. if (IsLayerAvailable(api, "VK_LAYER_KHRONOS_validation"))
  63. enabledLayers.Add("VK_LAYER_KHRONOS_validation");
  64. }
  65. foreach (var layer in options.EnabledLayers)
  66. enabledLayers.Add(layer);
  67. var ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Count];
  68. var ppEnabledLayers = stackalloc IntPtr[enabledLayers.Count];
  69. for (var i = 0; i < enabledExtensions.Count; i++)
  70. ppEnabledExtensions[i] = Marshal.StringToHGlobalAnsi(enabledExtensions[i]);
  71. var layers = enabledLayers.ToList();
  72. for (var i = 0; i < enabledLayers.Count; i++)
  73. ppEnabledLayers[i] = Marshal.StringToHGlobalAnsi(layers[i]);
  74. var instanceCreateInfo = new InstanceCreateInfo
  75. {
  76. SType = StructureType.InstanceCreateInfo,
  77. PApplicationInfo = &applicationInfo,
  78. PpEnabledExtensionNames = (byte**)ppEnabledExtensions,
  79. PpEnabledLayerNames = (byte**)ppEnabledLayers,
  80. EnabledExtensionCount = (uint)enabledExtensions.Count,
  81. EnabledLayerCount = (uint)enabledLayers.Count
  82. };
  83. api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
  84. Marshal.FreeHGlobal(applicationName);
  85. Marshal.FreeHGlobal(engineName);
  86. for (var i = 0; i < enabledExtensions.Count; i++) Marshal.FreeHGlobal(ppEnabledExtensions[i]);
  87. for (var i = 0; i < enabledLayers.Count; i++) Marshal.FreeHGlobal(ppEnabledLayers[i]);
  88. return new VulkanInstance(instance, api);
  89. }
  90. private static unsafe bool IsLayerAvailable(Vk api, string layerName)
  91. {
  92. uint layerPropertiesCount;
  93. api.EnumerateInstanceLayerProperties(&layerPropertiesCount, null).ThrowOnError();
  94. var layerProperties = new LayerProperties[layerPropertiesCount];
  95. fixed (LayerProperties* pLayerProperties = layerProperties)
  96. {
  97. api.EnumerateInstanceLayerProperties(&layerPropertiesCount, layerProperties).ThrowOnError();
  98. for (var i = 0; i < layerPropertiesCount; i++)
  99. {
  100. var currentLayerName = Marshal.PtrToStringAnsi((IntPtr)pLayerProperties[i].LayerName);
  101. if (currentLayerName == layerName) return true;
  102. }
  103. }
  104. return false;
  105. }
  106. }
  107. }