/* * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include namespace Gfx { static ErrorOr create_instance(uint32_t api_version) { 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; auto result = vkCreateInstance(&create_info, nullptr, &instance); if (result != VK_SUCCESS) { dbgln("vkCreateInstance returned {}", to_underlying(result)); return Error::from_string_literal("Application instance creation failed"); } return instance; } static ErrorOr pick_physical_device(VkInstance instance) { uint32_t device_count = 0; vkEnumeratePhysicalDevices(instance, &device_count, nullptr); if (device_count == 0) return Error::from_string_literal("Can't find any physical devices available"); Vector 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(); } static ErrorOr create_logical_device(VkPhysicalDevice physical_device) { VkDevice device; uint32_t queue_family_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr); Vector queue_families; queue_families.resize(queue_family_count); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families.data()); int graphics_queue_family_index = -1; for (int i = 0; i < static_cast(queue_families.size()); i++) { if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { graphics_queue_family_index = i; break; } } 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) { return Error::from_string_literal("Logical device creation failed"); } return device; } ErrorOr 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, }; } }