ladybird/Libraries/LibGfx/VulkanContext.cpp
Rocco Corsi d322c3a21f
Some checks are pending
CI / macOS, arm64, Sanitizer, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
LibGfx: VulkanContext coverity reports integer_overflow on index
Coverity static analysis reports that the code that scans the queue
families for one that has the graphics bit, can be -1 if none are
found, which could cause a problem when the -1 (signed) value is
used later as an index in a uint32_t (unsigned) variable.

Its not immediately clear how often this could occur, not finding
a queue family with the graphics bit, but adding some protecting
just in case.
2025-07-27 23:38:49 -04:00

133 lines
4.4 KiB
C++

/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Format.h>
#include <AK/Vector.h>
#include <LibGfx/VulkanContext.h>
namespace Gfx {
static 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;
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<VkPhysicalDevice> 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<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();
}
static 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());
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;
break;
}
}
if (!graphics_queue_family_found) {
return Error::from_string_literal("Graphics queue family not found");
}
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<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,
};
}
}