2024-07-03 17:23:27 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
2024-07-06 16:19:21 +00:00
|
|
|
#include <AK/Format.h>
|
2024-07-03 17:23:27 +00:00
|
|
|
#include <AK/Vector.h>
|
|
|
|
#include <LibCore/VulkanContext.h>
|
|
|
|
|
|
|
|
namespace Core {
|
|
|
|
|
|
|
|
ErrorOr<VkInstance> 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;
|
|
|
|
|
2024-07-06 16:19:21 +00:00
|
|
|
auto result = vkCreateInstance(&create_info, nullptr, &instance);
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
dbgln("vkCreateInstance returned {}", to_underlying(result));
|
2024-07-03 17:23:27 +00:00
|
|
|
return Error::from_string_view("Application instance creation failed"sv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<VkPhysicalDevice> pick_physical_device(VkInstance instance)
|
|
|
|
{
|
|
|
|
uint32_t device_count = 0;
|
|
|
|
vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
|
|
|
|
|
|
|
|
if (device_count == 0)
|
|
|
|
return Error::from_string_view("Can't find any physical devices available"sv);
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<VkDevice> create_logical_device(VkPhysicalDevice physical_device)
|
|
|
|
{
|
|
|
|
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());
|
|
|
|
|
|
|
|
int graphics_queue_family_index = -1;
|
|
|
|
for (int i = 0; i < static_cast<int>(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_view("Logical device creation failed"sv);
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|