VulkanInitialization.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. using Ryujinx.Common.Configuration;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.Graphics.GAL;
  4. using Silk.NET.Core;
  5. using Silk.NET.Vulkan;
  6. using Silk.NET.Vulkan.Extensions.EXT;
  7. using Silk.NET.Vulkan.Extensions.KHR;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Runtime.InteropServices;
  12. namespace Ryujinx.Graphics.Vulkan
  13. {
  14. public unsafe static class VulkanInitialization
  15. {
  16. private const uint InvalidIndex = uint.MaxValue;
  17. private static readonly uint _minimalVulkanVersion = Vk.Version11.Value;
  18. private static readonly uint _minimalInstanceVulkanVersion = Vk.Version12.Value;
  19. private static readonly uint _maximumVulkanVersion = Vk.Version12.Value;
  20. private const string AppName = "Ryujinx.Graphics.Vulkan";
  21. private const int QueuesCount = 2;
  22. private static readonly string[] _desirableExtensions =
  23. [
  24. ExtConditionalRendering.ExtensionName,
  25. ExtExtendedDynamicState.ExtensionName,
  26. ExtTransformFeedback.ExtensionName,
  27. KhrDrawIndirectCount.ExtensionName,
  28. KhrPushDescriptor.ExtensionName,
  29. ExtExternalMemoryHost.ExtensionName,
  30. "VK_EXT_blend_operation_advanced",
  31. "VK_EXT_custom_border_color",
  32. "VK_EXT_descriptor_indexing", // Enabling this works around an issue with disposed buffer bindings on RADV.
  33. "VK_EXT_fragment_shader_interlock",
  34. "VK_EXT_index_type_uint8",
  35. "VK_EXT_primitive_topology_list_restart",
  36. "VK_EXT_robustness2",
  37. "VK_EXT_shader_stencil_export",
  38. "VK_KHR_shader_float16_int8",
  39. "VK_EXT_shader_subgroup_ballot",
  40. "VK_NV_geometry_shader_passthrough",
  41. "VK_NV_viewport_array2",
  42. "VK_EXT_depth_clip_control",
  43. "VK_KHR_portability_subset", // As per spec, we should enable this if present.
  44. "VK_EXT_4444_formats",
  45. "VK_KHR_8bit_storage",
  46. "VK_KHR_maintenance2",
  47. "VK_EXT_attachment_feedback_loop_layout",
  48. "VK_EXT_attachment_feedback_loop_dynamic_state"
  49. ];
  50. private static readonly string[] _requiredExtensions =
  51. [
  52. KhrSwapchain.ExtensionName
  53. ];
  54. internal static VulkanInstance CreateInstance(Vk api, GraphicsDebugLevel logLevel, string[] requiredExtensions)
  55. {
  56. List<string> enabledLayers = [];
  57. IReadOnlySet<string> instanceExtensions = VulkanInstance.GetInstanceExtensions(api);
  58. IReadOnlySet<string> instanceLayers = VulkanInstance.GetInstanceLayers(api);
  59. void AddAvailableLayer(string layerName)
  60. {
  61. if (instanceLayers.Contains(layerName))
  62. {
  63. enabledLayers.Add(layerName);
  64. }
  65. else
  66. {
  67. Logger.Warning?.Print(LogClass.Gpu, $"Missing layer {layerName}");
  68. }
  69. }
  70. if (logLevel != GraphicsDebugLevel.None)
  71. {
  72. AddAvailableLayer("VK_LAYER_KHRONOS_validation");
  73. }
  74. string[] enabledExtensions = requiredExtensions;
  75. if (instanceExtensions.Contains("VK_EXT_debug_utils"))
  76. {
  77. enabledExtensions = enabledExtensions.Append(ExtDebugUtils.ExtensionName).ToArray();
  78. }
  79. IntPtr appName = Marshal.StringToHGlobalAnsi(AppName);
  80. ApplicationInfo applicationInfo = new()
  81. {
  82. PApplicationName = (byte*)appName,
  83. ApplicationVersion = 1,
  84. PEngineName = (byte*)appName,
  85. EngineVersion = 1,
  86. ApiVersion = _maximumVulkanVersion,
  87. };
  88. nint* ppEnabledExtensions = stackalloc nint[enabledExtensions.Length];
  89. nint* ppEnabledLayers = stackalloc nint[enabledLayers.Count];
  90. for (int i = 0; i < enabledExtensions.Length; i++)
  91. {
  92. ppEnabledExtensions[i] = Marshal.StringToHGlobalAnsi(enabledExtensions[i]);
  93. }
  94. for (int i = 0; i < enabledLayers.Count; i++)
  95. {
  96. ppEnabledLayers[i] = Marshal.StringToHGlobalAnsi(enabledLayers[i]);
  97. }
  98. InstanceCreateInfo instanceCreateInfo = new()
  99. {
  100. SType = StructureType.InstanceCreateInfo,
  101. PApplicationInfo = &applicationInfo,
  102. PpEnabledExtensionNames = (byte**)ppEnabledExtensions,
  103. PpEnabledLayerNames = (byte**)ppEnabledLayers,
  104. EnabledExtensionCount = (uint)enabledExtensions.Length,
  105. EnabledLayerCount = (uint)enabledLayers.Count,
  106. };
  107. Result result = VulkanInstance.Create(api, ref instanceCreateInfo, out VulkanInstance instance);
  108. Marshal.FreeHGlobal(appName);
  109. for (int i = 0; i < enabledExtensions.Length; i++)
  110. {
  111. Marshal.FreeHGlobal(ppEnabledExtensions[i]);
  112. }
  113. for (int i = 0; i < enabledLayers.Count; i++)
  114. {
  115. Marshal.FreeHGlobal(ppEnabledLayers[i]);
  116. }
  117. result.ThrowOnError();
  118. return instance;
  119. }
  120. internal static VulkanPhysicalDevice FindSuitablePhysicalDevice(Vk api, VulkanInstance instance, SurfaceKHR surface, string preferredGpuId)
  121. {
  122. instance.EnumeratePhysicalDevices(out VulkanPhysicalDevice[] physicalDevices).ThrowOnError();
  123. // First we try to pick the user preferred GPU.
  124. for (int i = 0; i < physicalDevices.Length; i++)
  125. {
  126. if (IsPreferredAndSuitableDevice(api, physicalDevices[i], surface, preferredGpuId))
  127. {
  128. return physicalDevices[i];
  129. }
  130. }
  131. // If we fail to do that, just use the first compatible GPU.
  132. for (int i = 0; i < physicalDevices.Length; i++)
  133. {
  134. if (IsSuitableDevice(api, physicalDevices[i], surface))
  135. {
  136. return physicalDevices[i];
  137. }
  138. }
  139. throw new VulkanException("Initialization failed, none of the available GPUs meets the minimum requirements.");
  140. }
  141. internal static DeviceInfo[] GetSuitablePhysicalDevices(Vk api)
  142. {
  143. IntPtr appName = Marshal.StringToHGlobalAnsi(AppName);
  144. ApplicationInfo applicationInfo = new()
  145. {
  146. PApplicationName = (byte*)appName,
  147. ApplicationVersion = 1,
  148. PEngineName = (byte*)appName,
  149. EngineVersion = 1,
  150. ApiVersion = _maximumVulkanVersion,
  151. };
  152. InstanceCreateInfo instanceCreateInfo = new()
  153. {
  154. SType = StructureType.InstanceCreateInfo,
  155. PApplicationInfo = &applicationInfo,
  156. PpEnabledExtensionNames = null,
  157. PpEnabledLayerNames = null,
  158. EnabledExtensionCount = 0,
  159. EnabledLayerCount = 0,
  160. };
  161. Result result = VulkanInstance.Create(api, ref instanceCreateInfo, out VulkanInstance rawInstance);
  162. Marshal.FreeHGlobal(appName);
  163. result.ThrowOnError();
  164. using VulkanInstance instance = rawInstance;
  165. // We currently assume that the instance is compatible with Vulkan 1.2
  166. // TODO: Remove this once we relax our initialization codepaths.
  167. if (instance.InstanceVersion < _minimalInstanceVulkanVersion)
  168. {
  169. return [];
  170. }
  171. instance.EnumeratePhysicalDevices(out VulkanPhysicalDevice[] physicalDevices).ThrowOnError();
  172. List<DeviceInfo> deviceInfos = [];
  173. foreach (VulkanPhysicalDevice physicalDevice in physicalDevices)
  174. {
  175. if (physicalDevice.PhysicalDeviceProperties.ApiVersion < _minimalVulkanVersion)
  176. {
  177. continue;
  178. }
  179. deviceInfos.Add(physicalDevice.ToDeviceInfo());
  180. }
  181. return deviceInfos.ToArray();
  182. }
  183. private static bool IsPreferredAndSuitableDevice(Vk api, VulkanPhysicalDevice physicalDevice, SurfaceKHR surface, string preferredGpuId)
  184. {
  185. if (physicalDevice.Id != preferredGpuId)
  186. {
  187. return false;
  188. }
  189. return IsSuitableDevice(api, physicalDevice, surface);
  190. }
  191. private static bool IsSuitableDevice(Vk api, VulkanPhysicalDevice physicalDevice, SurfaceKHR surface)
  192. {
  193. int extensionMatches = 0;
  194. foreach (string requiredExtension in _requiredExtensions)
  195. {
  196. if (physicalDevice.IsDeviceExtensionPresent(requiredExtension))
  197. {
  198. extensionMatches++;
  199. }
  200. }
  201. return extensionMatches == _requiredExtensions.Length && FindSuitableQueueFamily(api, physicalDevice, surface, out _) != InvalidIndex;
  202. }
  203. internal static uint FindSuitableQueueFamily(Vk api, VulkanPhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
  204. {
  205. const QueueFlags RequiredFlags = QueueFlags.GraphicsBit | QueueFlags.ComputeBit;
  206. KhrSurface khrSurface = new(api.Context);
  207. for (uint index = 0; index < physicalDevice.QueueFamilyProperties.Length; index++)
  208. {
  209. ref QueueFamilyProperties property = ref physicalDevice.QueueFamilyProperties[index];
  210. khrSurface.GetPhysicalDeviceSurfaceSupport(physicalDevice.PhysicalDevice, index, surface, out Bool32 surfaceSupported).ThrowOnError();
  211. if (property.QueueFlags.HasFlag(RequiredFlags) && surfaceSupported)
  212. {
  213. queueCount = property.QueueCount;
  214. return index;
  215. }
  216. }
  217. queueCount = 0;
  218. return InvalidIndex;
  219. }
  220. internal static Device CreateDevice(Vk api, VulkanPhysicalDevice physicalDevice, uint queueFamilyIndex, uint queueCount)
  221. {
  222. if (queueCount > QueuesCount)
  223. {
  224. queueCount = QueuesCount;
  225. }
  226. float* queuePriorities = stackalloc float[(int)queueCount];
  227. for (int i = 0; i < queueCount; i++)
  228. {
  229. queuePriorities[i] = 1f;
  230. }
  231. DeviceQueueCreateInfo queueCreateInfo = new()
  232. {
  233. SType = StructureType.DeviceQueueCreateInfo,
  234. QueueFamilyIndex = queueFamilyIndex,
  235. QueueCount = queueCount,
  236. PQueuePriorities = queuePriorities,
  237. };
  238. bool useRobustBufferAccess = VendorUtils.FromId(physicalDevice.PhysicalDeviceProperties.VendorID) == Vendor.Nvidia;
  239. PhysicalDeviceFeatures2 features2 = new()
  240. {
  241. SType = StructureType.PhysicalDeviceFeatures2,
  242. };
  243. PhysicalDeviceVulkan11Features supportedFeaturesVk11 = new()
  244. {
  245. SType = StructureType.PhysicalDeviceVulkan11Features,
  246. PNext = features2.PNext,
  247. };
  248. features2.PNext = &supportedFeaturesVk11;
  249. PhysicalDeviceCustomBorderColorFeaturesEXT supportedFeaturesCustomBorderColor = new()
  250. {
  251. SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt,
  252. PNext = features2.PNext,
  253. };
  254. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color"))
  255. {
  256. features2.PNext = &supportedFeaturesCustomBorderColor;
  257. }
  258. PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT supportedFeaturesPrimitiveTopologyListRestart = new()
  259. {
  260. SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt,
  261. PNext = features2.PNext,
  262. };
  263. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_primitive_topology_list_restart"))
  264. {
  265. features2.PNext = &supportedFeaturesPrimitiveTopologyListRestart;
  266. }
  267. PhysicalDeviceTransformFeedbackFeaturesEXT supportedFeaturesTransformFeedback = new()
  268. {
  269. SType = StructureType.PhysicalDeviceTransformFeedbackFeaturesExt,
  270. PNext = features2.PNext,
  271. };
  272. if (physicalDevice.IsDeviceExtensionPresent(ExtTransformFeedback.ExtensionName))
  273. {
  274. features2.PNext = &supportedFeaturesTransformFeedback;
  275. }
  276. PhysicalDeviceRobustness2FeaturesEXT supportedFeaturesRobustness2 = new()
  277. {
  278. SType = StructureType.PhysicalDeviceRobustness2FeaturesExt,
  279. };
  280. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
  281. {
  282. supportedFeaturesRobustness2.PNext = features2.PNext;
  283. features2.PNext = &supportedFeaturesRobustness2;
  284. }
  285. PhysicalDeviceDepthClipControlFeaturesEXT supportedFeaturesDepthClipControl = new()
  286. {
  287. SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt,
  288. PNext = features2.PNext,
  289. };
  290. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_depth_clip_control"))
  291. {
  292. features2.PNext = &supportedFeaturesDepthClipControl;
  293. }
  294. PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT supportedFeaturesAttachmentFeedbackLoopLayout = new()
  295. {
  296. SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
  297. PNext = features2.PNext,
  298. };
  299. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout"))
  300. {
  301. features2.PNext = &supportedFeaturesAttachmentFeedbackLoopLayout;
  302. }
  303. PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT supportedFeaturesDynamicAttachmentFeedbackLoopLayout = new()
  304. {
  305. SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
  306. PNext = features2.PNext,
  307. };
  308. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state"))
  309. {
  310. features2.PNext = &supportedFeaturesDynamicAttachmentFeedbackLoopLayout;
  311. }
  312. PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new()
  313. {
  314. SType = StructureType.PhysicalDeviceVulkan12Features,
  315. PNext = features2.PNext,
  316. };
  317. features2.PNext = &supportedPhysicalDeviceVulkan12Features;
  318. api.GetPhysicalDeviceFeatures2(physicalDevice.PhysicalDevice, &features2);
  319. PhysicalDeviceFeatures supportedFeatures = features2.Features;
  320. PhysicalDeviceFeatures features = new()
  321. {
  322. DepthBiasClamp = supportedFeatures.DepthBiasClamp,
  323. DepthClamp = supportedFeatures.DepthClamp,
  324. DualSrcBlend = supportedFeatures.DualSrcBlend,
  325. FragmentStoresAndAtomics = supportedFeatures.FragmentStoresAndAtomics,
  326. GeometryShader = supportedFeatures.GeometryShader,
  327. ImageCubeArray = supportedFeatures.ImageCubeArray,
  328. IndependentBlend = supportedFeatures.IndependentBlend,
  329. LogicOp = supportedFeatures.LogicOp,
  330. OcclusionQueryPrecise = supportedFeatures.OcclusionQueryPrecise,
  331. MultiViewport = supportedFeatures.MultiViewport,
  332. PipelineStatisticsQuery = supportedFeatures.PipelineStatisticsQuery,
  333. SamplerAnisotropy = supportedFeatures.SamplerAnisotropy,
  334. ShaderClipDistance = supportedFeatures.ShaderClipDistance,
  335. ShaderFloat64 = supportedFeatures.ShaderFloat64,
  336. ShaderImageGatherExtended = supportedFeatures.ShaderImageGatherExtended,
  337. ShaderStorageImageMultisample = supportedFeatures.ShaderStorageImageMultisample,
  338. ShaderStorageImageReadWithoutFormat = supportedFeatures.ShaderStorageImageReadWithoutFormat,
  339. ShaderStorageImageWriteWithoutFormat = supportedFeatures.ShaderStorageImageWriteWithoutFormat,
  340. TessellationShader = supportedFeatures.TessellationShader,
  341. VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics,
  342. RobustBufferAccess = useRobustBufferAccess,
  343. SampleRateShading = supportedFeatures.SampleRateShading,
  344. };
  345. void* pExtendedFeatures = null;
  346. PhysicalDeviceTransformFeedbackFeaturesEXT featuresTransformFeedback;
  347. if (physicalDevice.IsDeviceExtensionPresent(ExtTransformFeedback.ExtensionName))
  348. {
  349. featuresTransformFeedback = new PhysicalDeviceTransformFeedbackFeaturesEXT
  350. {
  351. SType = StructureType.PhysicalDeviceTransformFeedbackFeaturesExt,
  352. PNext = pExtendedFeatures,
  353. TransformFeedback = supportedFeaturesTransformFeedback.TransformFeedback,
  354. };
  355. pExtendedFeatures = &featuresTransformFeedback;
  356. }
  357. PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT featuresPrimitiveTopologyListRestart;
  358. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_primitive_topology_list_restart"))
  359. {
  360. featuresPrimitiveTopologyListRestart = new PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT
  361. {
  362. SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt,
  363. PNext = pExtendedFeatures,
  364. PrimitiveTopologyListRestart = supportedFeaturesPrimitiveTopologyListRestart.PrimitiveTopologyListRestart,
  365. PrimitiveTopologyPatchListRestart = supportedFeaturesPrimitiveTopologyListRestart.PrimitiveTopologyPatchListRestart,
  366. };
  367. pExtendedFeatures = &featuresPrimitiveTopologyListRestart;
  368. }
  369. PhysicalDeviceRobustness2FeaturesEXT featuresRobustness2;
  370. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
  371. {
  372. featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT
  373. {
  374. SType = StructureType.PhysicalDeviceRobustness2FeaturesExt,
  375. PNext = pExtendedFeatures,
  376. NullDescriptor = supportedFeaturesRobustness2.NullDescriptor,
  377. };
  378. pExtendedFeatures = &featuresRobustness2;
  379. }
  380. PhysicalDeviceExtendedDynamicStateFeaturesEXT featuresExtendedDynamicState = new()
  381. {
  382. SType = StructureType.PhysicalDeviceExtendedDynamicStateFeaturesExt,
  383. PNext = pExtendedFeatures,
  384. ExtendedDynamicState = physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName),
  385. };
  386. pExtendedFeatures = &featuresExtendedDynamicState;
  387. PhysicalDeviceVulkan11Features featuresVk11 = new()
  388. {
  389. SType = StructureType.PhysicalDeviceVulkan11Features,
  390. PNext = pExtendedFeatures,
  391. ShaderDrawParameters = supportedFeaturesVk11.ShaderDrawParameters,
  392. };
  393. pExtendedFeatures = &featuresVk11;
  394. PhysicalDeviceVulkan12Features featuresVk12 = new()
  395. {
  396. SType = StructureType.PhysicalDeviceVulkan12Features,
  397. PNext = pExtendedFeatures,
  398. DescriptorIndexing = supportedPhysicalDeviceVulkan12Features.DescriptorIndexing,
  399. DrawIndirectCount = supportedPhysicalDeviceVulkan12Features.DrawIndirectCount,
  400. UniformBufferStandardLayout = supportedPhysicalDeviceVulkan12Features.UniformBufferStandardLayout,
  401. UniformAndStorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.UniformAndStorageBuffer8BitAccess,
  402. StorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.StorageBuffer8BitAccess,
  403. };
  404. pExtendedFeatures = &featuresVk12;
  405. PhysicalDeviceIndexTypeUint8FeaturesEXT featuresIndexU8;
  406. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"))
  407. {
  408. featuresIndexU8 = new PhysicalDeviceIndexTypeUint8FeaturesEXT
  409. {
  410. SType = StructureType.PhysicalDeviceIndexTypeUint8FeaturesExt,
  411. PNext = pExtendedFeatures,
  412. IndexTypeUint8 = true,
  413. };
  414. pExtendedFeatures = &featuresIndexU8;
  415. }
  416. PhysicalDeviceFragmentShaderInterlockFeaturesEXT featuresFragmentShaderInterlock;
  417. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_fragment_shader_interlock"))
  418. {
  419. featuresFragmentShaderInterlock = new PhysicalDeviceFragmentShaderInterlockFeaturesEXT
  420. {
  421. SType = StructureType.PhysicalDeviceFragmentShaderInterlockFeaturesExt,
  422. PNext = pExtendedFeatures,
  423. FragmentShaderPixelInterlock = true,
  424. };
  425. pExtendedFeatures = &featuresFragmentShaderInterlock;
  426. }
  427. PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColor;
  428. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color") &&
  429. supportedFeaturesCustomBorderColor.CustomBorderColors &&
  430. supportedFeaturesCustomBorderColor.CustomBorderColorWithoutFormat)
  431. {
  432. featuresCustomBorderColor = new PhysicalDeviceCustomBorderColorFeaturesEXT
  433. {
  434. SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt,
  435. PNext = pExtendedFeatures,
  436. CustomBorderColors = true,
  437. CustomBorderColorWithoutFormat = true,
  438. };
  439. pExtendedFeatures = &featuresCustomBorderColor;
  440. }
  441. PhysicalDeviceDepthClipControlFeaturesEXT featuresDepthClipControl;
  442. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_depth_clip_control") &&
  443. supportedFeaturesDepthClipControl.DepthClipControl)
  444. {
  445. featuresDepthClipControl = new PhysicalDeviceDepthClipControlFeaturesEXT
  446. {
  447. SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt,
  448. PNext = pExtendedFeatures,
  449. DepthClipControl = true,
  450. };
  451. pExtendedFeatures = &featuresDepthClipControl;
  452. }
  453. PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoopLayout;
  454. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout") &&
  455. supportedFeaturesAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopLayout)
  456. {
  457. featuresAttachmentFeedbackLoopLayout = new()
  458. {
  459. SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
  460. PNext = pExtendedFeatures,
  461. AttachmentFeedbackLoopLayout = true,
  462. };
  463. pExtendedFeatures = &featuresAttachmentFeedbackLoopLayout;
  464. }
  465. PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoopLayout;
  466. if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state") &&
  467. supportedFeaturesDynamicAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopDynamicState)
  468. {
  469. featuresDynamicAttachmentFeedbackLoopLayout = new()
  470. {
  471. SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
  472. PNext = pExtendedFeatures,
  473. AttachmentFeedbackLoopDynamicState = true,
  474. };
  475. pExtendedFeatures = &featuresDynamicAttachmentFeedbackLoopLayout;
  476. }
  477. string[] enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
  478. nint* ppEnabledExtensions = stackalloc nint[enabledExtensions.Length];
  479. for (int i = 0; i < enabledExtensions.Length; i++)
  480. {
  481. ppEnabledExtensions[i] = Marshal.StringToHGlobalAnsi(enabledExtensions[i]);
  482. }
  483. DeviceCreateInfo deviceCreateInfo = new()
  484. {
  485. SType = StructureType.DeviceCreateInfo,
  486. PNext = pExtendedFeatures,
  487. QueueCreateInfoCount = 1,
  488. PQueueCreateInfos = &queueCreateInfo,
  489. PpEnabledExtensionNames = (byte**)ppEnabledExtensions,
  490. EnabledExtensionCount = (uint)enabledExtensions.Length,
  491. PEnabledFeatures = &features,
  492. };
  493. api.CreateDevice(physicalDevice.PhysicalDevice, in deviceCreateInfo, null, out Device device).ThrowOnError();
  494. for (int i = 0; i < enabledExtensions.Length; i++)
  495. {
  496. Marshal.FreeHGlobal(ppEnabledExtensions[i]);
  497. }
  498. return device;
  499. }
  500. }
  501. }