| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-06 18:19:21 +02:00
										 |  |  | #include <AK/Format.h>
 | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  | #include <AK/Vector.h>
 | 
					
						
							| 
									
										
										
										
											2024-09-26 17:27:58 +02:00
										 |  |  | #include <LibGfx/VulkanContext.h>
 | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-26 17:27:58 +02:00
										 |  |  | namespace Gfx { | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 18:29:33 +02:00
										 |  |  | static ErrorOr<VkInstance> create_instance(uint32_t api_version) | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     VkInstance instance; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VkApplicationInfo app_info {}; | 
					
						
							|  |  |  |     app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; | 
					
						
							|  |  |  |     app_info.pApplicationName = "Ladybird"; | 
					
						
							|  |  |  |     app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0); | 
					
						
							|  |  |  |     app_info.pEngineName = nullptr; | 
					
						
							|  |  |  |     app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); | 
					
						
							|  |  |  |     app_info.apiVersion = api_version; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VkInstanceCreateInfo create_info {}; | 
					
						
							|  |  |  |     create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; | 
					
						
							|  |  |  |     create_info.pApplicationInfo = &app_info; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-06 18:19:21 +02:00
										 |  |  |     auto result = vkCreateInstance(&create_info, nullptr, &instance); | 
					
						
							|  |  |  |     if (result != VK_SUCCESS) { | 
					
						
							|  |  |  |         dbgln("vkCreateInstance returned {}", to_underlying(result)); | 
					
						
							| 
									
										
										
										
											2024-09-05 15:06:15 +04:00
										 |  |  |         return Error::from_string_literal("Application instance creation failed"); | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return instance; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 18:29:33 +02:00
										 |  |  | static ErrorOr<VkPhysicalDevice> pick_physical_device(VkInstance instance) | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     uint32_t device_count = 0; | 
					
						
							|  |  |  |     vkEnumeratePhysicalDevices(instance, &device_count, nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (device_count == 0) | 
					
						
							| 
									
										
										
										
											2024-09-05 15:06:15 +04:00
										 |  |  |         return Error::from_string_literal("Can't find any physical devices available"); | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Vector<VkPhysicalDevice> devices; | 
					
						
							|  |  |  |     devices.resize(device_count); | 
					
						
							|  |  |  |     vkEnumeratePhysicalDevices(instance, &device_count, devices.data()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VkPhysicalDevice picked_device = VK_NULL_HANDLE; | 
					
						
							|  |  |  |     // Pick discrete GPU or the first device in the list
 | 
					
						
							|  |  |  |     for (auto const& device : devices) { | 
					
						
							|  |  |  |         if (picked_device == VK_NULL_HANDLE) | 
					
						
							|  |  |  |             picked_device = device; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         VkPhysicalDeviceProperties device_properties; | 
					
						
							|  |  |  |         vkGetPhysicalDeviceProperties(device, &device_properties); | 
					
						
							|  |  |  |         if (device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) | 
					
						
							|  |  |  |             picked_device = device; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (picked_device != VK_NULL_HANDLE) | 
					
						
							|  |  |  |         return picked_device; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VERIFY_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 18:29:33 +02:00
										 |  |  | static ErrorOr<VkDevice> create_logical_device(VkPhysicalDevice physical_device) | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     VkDevice device; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uint32_t queue_family_count = 0; | 
					
						
							|  |  |  |     vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr); | 
					
						
							|  |  |  |     Vector<VkQueueFamilyProperties> queue_families; | 
					
						
							|  |  |  |     queue_families.resize(queue_family_count); | 
					
						
							|  |  |  |     vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families.data()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-22 12:23:13 -04:00
										 |  |  |     bool graphics_queue_family_found = false; | 
					
						
							|  |  |  |     uint32_t graphics_queue_family_index = 0; | 
					
						
							|  |  |  |     for (; graphics_queue_family_index < queue_families.size(); ++graphics_queue_family_index) { | 
					
						
							|  |  |  |         if (queue_families[graphics_queue_family_index].queueFlags & VK_QUEUE_GRAPHICS_BIT) { | 
					
						
							|  |  |  |             graphics_queue_family_found = true; | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-22 12:23:13 -04:00
										 |  |  |     if (!graphics_queue_family_found) { | 
					
						
							|  |  |  |         return Error::from_string_literal("Graphics queue family not found"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  |     VkDeviceQueueCreateInfo queue_create_info {}; | 
					
						
							|  |  |  |     queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; | 
					
						
							|  |  |  |     queue_create_info.queueFamilyIndex = graphics_queue_family_index; | 
					
						
							|  |  |  |     queue_create_info.queueCount = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     float const queue_priority = 1.0f; | 
					
						
							|  |  |  |     queue_create_info.pQueuePriorities = &queue_priority; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VkPhysicalDeviceFeatures deviceFeatures {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VkDeviceCreateInfo create_device_info {}; | 
					
						
							|  |  |  |     create_device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; | 
					
						
							|  |  |  |     create_device_info.pQueueCreateInfos = &queue_create_info; | 
					
						
							|  |  |  |     create_device_info.queueCreateInfoCount = 1; | 
					
						
							|  |  |  |     create_device_info.pEnabledFeatures = &deviceFeatures; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (vkCreateDevice(physical_device, &create_device_info, nullptr, &device) != VK_SUCCESS) { | 
					
						
							| 
									
										
										
										
											2024-09-05 15:06:15 +04:00
										 |  |  |         return Error::from_string_literal("Logical device creation failed"); | 
					
						
							| 
									
										
										
										
											2024-07-03 19:23:27 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return device; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ErrorOr<VulkanContext> create_vulkan_context() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint32_t const api_version = VK_API_VERSION_1_0; | 
					
						
							|  |  |  |     auto* instance = TRY(create_instance(api_version)); | 
					
						
							|  |  |  |     auto* physical_device = TRY(pick_physical_device(instance)); | 
					
						
							|  |  |  |     auto* logical_device = TRY(create_logical_device(physical_device)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VkQueue graphics_queue; | 
					
						
							|  |  |  |     vkGetDeviceQueue(logical_device, 0, 0, &graphics_queue); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return VulkanContext { | 
					
						
							|  |  |  |         .api_version = api_version, | 
					
						
							|  |  |  |         .instance = instance, | 
					
						
							|  |  |  |         .physical_device = physical_device, | 
					
						
							|  |  |  |         .logical_device = logical_device, | 
					
						
							|  |  |  |         .graphics_queue = graphics_queue, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |