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();
|
|
|
|
}
|
|
|
|
|
2025-08-14 18:55:26 -04:00
|
|
|
static ErrorOr<VkDevice> create_logical_device(VkPhysicalDevice physical_device, uint32_t* graphics_queue_family)
|
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");
|
|
|
|
}
|
|
|
|
|
2025-08-14 18:55:26 -04:00
|
|
|
*graphics_queue_family = graphics_queue_family_index;
|
|
|
|
|
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 {};
|
2025-08-19 12:07:03 -04:00
|
|
|
#ifdef USE_VULKAN_IMAGES
|
2025-08-14 19:00:44 -04:00
|
|
|
char const* device_extensions[] = {
|
|
|
|
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
|
|
|
|
VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME
|
|
|
|
};
|
2025-08-19 12:07:03 -04:00
|
|
|
uint32_t device_extension_count = array_size(device_extensions);
|
|
|
|
#else
|
|
|
|
const char** device_extensions = nullptr;
|
|
|
|
uint32_t device_extension_count = 0;
|
|
|
|
#endif
|
2024-07-03 19:23:27 +02:00
|
|
|
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;
|
2025-08-19 12:07:03 -04:00
|
|
|
create_device_info.enabledExtensionCount = device_extension_count;
|
2025-08-14 19:00:44 -04:00
|
|
|
create_device_info.ppEnabledExtensionNames = device_extensions;
|
2024-07-03 19:23:27 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-08-19 12:07:03 -04:00
|
|
|
#ifdef USE_VULKAN_IMAGES
|
2025-08-14 18:57:54 -04:00
|
|
|
static ErrorOr<VkCommandPool> create_command_pool(VkDevice logical_device, uint32_t queue_family_index)
|
|
|
|
{
|
|
|
|
VkCommandPoolCreateInfo command_pool_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
|
|
|
.queueFamilyIndex = queue_family_index,
|
|
|
|
};
|
|
|
|
VkCommandPool command_pool = VK_NULL_HANDLE;
|
|
|
|
VkResult result = vkCreateCommandPool(logical_device, &command_pool_info, nullptr, &command_pool);
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
dbgln("vkCreateCommandPool returned {}", to_underlying(result));
|
|
|
|
return Error::from_string_literal("command pool creation failed");
|
|
|
|
}
|
|
|
|
return command_pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ErrorOr<VkCommandBuffer> allocate_command_buffer(VkDevice logical_device, VkCommandPool commandPool)
|
|
|
|
{
|
|
|
|
VkCommandBufferAllocateInfo command_buffer_alloc_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.commandPool = commandPool,
|
|
|
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
|
|
.commandBufferCount = 1,
|
|
|
|
};
|
|
|
|
VkCommandBuffer command_buffer = VK_NULL_HANDLE;
|
|
|
|
VkResult result = vkAllocateCommandBuffers(logical_device, &command_buffer_alloc_info, &command_buffer);
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
dbgln("vkAllocateCommandBuffers returned {}", to_underlying(result));
|
|
|
|
return Error::from_string_literal("command buffer allocation failed");
|
|
|
|
}
|
|
|
|
return command_buffer;
|
|
|
|
}
|
2025-08-19 12:07:03 -04:00
|
|
|
#endif
|
2025-08-14 18:57:54 -04:00
|
|
|
|
2024-07-03 19:23:27 +02:00
|
|
|
ErrorOr<VulkanContext> create_vulkan_context()
|
|
|
|
{
|
2025-08-14 19:00:44 -04:00
|
|
|
uint32_t const api_version = VK_API_VERSION_1_1; // v1.1 needed for vkGetPhysicalDeviceFormatProperties2
|
2024-07-03 19:23:27 +02:00
|
|
|
auto* instance = TRY(create_instance(api_version));
|
|
|
|
auto* physical_device = TRY(pick_physical_device(instance));
|
|
|
|
|
2025-08-14 18:55:26 -04:00
|
|
|
uint32_t graphics_queue_family = 0;
|
|
|
|
auto* logical_device = TRY(create_logical_device(physical_device, &graphics_queue_family));
|
2024-07-03 19:23:27 +02:00
|
|
|
VkQueue graphics_queue;
|
2025-08-14 18:55:26 -04:00
|
|
|
vkGetDeviceQueue(logical_device, graphics_queue_family, 0, &graphics_queue);
|
2024-07-03 19:23:27 +02:00
|
|
|
|
2025-08-19 12:07:03 -04:00
|
|
|
#ifdef USE_VULKAN_IMAGES
|
2025-08-14 18:57:54 -04:00
|
|
|
VkCommandPool command_pool = TRY(create_command_pool(logical_device, graphics_queue_family));
|
|
|
|
VkCommandBuffer command_buffer = TRY(allocate_command_buffer(logical_device, command_pool));
|
|
|
|
|
2025-08-19 17:23:49 +02:00
|
|
|
auto pfn_vk_get_memory_fd_khr = reinterpret_cast<PFN_vkGetMemoryFdKHR>(vkGetDeviceProcAddr(logical_device, "vkGetMemoryFdKHR"));
|
2025-08-14 19:00:44 -04:00
|
|
|
if (pfn_vk_get_memory_fd_khr == nullptr) {
|
|
|
|
return Error::from_string_literal("vkGetMemoryFdKHR unavailable");
|
|
|
|
}
|
2025-08-19 17:23:49 +02:00
|
|
|
auto pfn_vk_get_image_drm_format_modifier_properties_khr = reinterpret_cast<PFN_vkGetImageDrmFormatModifierPropertiesEXT>(vkGetDeviceProcAddr(logical_device, "vkGetImageDrmFormatModifierPropertiesEXT"));
|
2025-08-14 19:00:44 -04:00
|
|
|
if (pfn_vk_get_image_drm_format_modifier_properties_khr == nullptr) {
|
|
|
|
return Error::from_string_literal("vkGetImageDrmFormatModifierPropertiesEXT unavailable");
|
|
|
|
}
|
2025-08-19 12:07:03 -04:00
|
|
|
#endif
|
2025-08-14 19:00:44 -04:00
|
|
|
|
2024-07-03 19:23:27 +02:00
|
|
|
return VulkanContext {
|
|
|
|
.api_version = api_version,
|
|
|
|
.instance = instance,
|
|
|
|
.physical_device = physical_device,
|
|
|
|
.logical_device = logical_device,
|
|
|
|
.graphics_queue = graphics_queue,
|
2025-08-14 18:55:26 -04:00
|
|
|
.graphics_queue_family = graphics_queue_family,
|
2025-08-19 12:07:03 -04:00
|
|
|
#ifdef USE_VULKAN_IMAGES
|
2025-08-14 18:57:54 -04:00
|
|
|
.command_pool = command_pool,
|
|
|
|
.command_buffer = command_buffer,
|
2025-08-14 19:00:44 -04:00
|
|
|
.ext_procs = {
|
|
|
|
.get_memory_fd = pfn_vk_get_memory_fd_khr,
|
|
|
|
.get_image_drm_format_modifier_properties = pfn_vk_get_image_drm_format_modifier_properties_khr,
|
|
|
|
},
|
2025-08-19 12:07:03 -04:00
|
|
|
#endif
|
2025-08-14 19:00:44 -04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2025-08-19 12:07:03 -04:00
|
|
|
#ifdef USE_VULKAN_IMAGES
|
2025-08-14 19:00:44 -04:00
|
|
|
VulkanImage::~VulkanImage()
|
|
|
|
{
|
|
|
|
if (image != VK_NULL_HANDLE) {
|
|
|
|
vkDestroyImage(context.logical_device, image, nullptr);
|
|
|
|
}
|
|
|
|
if (memory != VK_NULL_HANDLE) {
|
|
|
|
vkFreeMemory(context.logical_device, memory, nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanImage::transition_layout(VkImageLayout old_layout, VkImageLayout new_layout)
|
|
|
|
{
|
|
|
|
vkResetCommandBuffer(context.command_buffer, 0);
|
|
|
|
VkCommandBufferBeginInfo begin_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
|
|
.pInheritanceInfo = nullptr,
|
|
|
|
};
|
|
|
|
vkBeginCommandBuffer(context.command_buffer, &begin_info);
|
|
|
|
VkImageMemoryBarrier imageMemoryBarrier = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.srcAccessMask = 0,
|
|
|
|
.dstAccessMask = 0,
|
|
|
|
.oldLayout = old_layout,
|
|
|
|
.newLayout = new_layout,
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
.image = image,
|
|
|
|
.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 },
|
|
|
|
};
|
|
|
|
vkCmdPipelineBarrier(context.command_buffer,
|
|
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
|
|
0,
|
|
|
|
0, nullptr,
|
|
|
|
0, nullptr,
|
|
|
|
1, &imageMemoryBarrier);
|
|
|
|
vkEndCommandBuffer(context.command_buffer);
|
|
|
|
VkSubmitInfo submit_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.waitSemaphoreCount = 0,
|
|
|
|
.pWaitSemaphores = nullptr,
|
|
|
|
.pWaitDstStageMask = nullptr,
|
|
|
|
.commandBufferCount = 1,
|
|
|
|
.pCommandBuffers = &context.command_buffer,
|
|
|
|
.signalSemaphoreCount = 0,
|
|
|
|
.pSignalSemaphores = nullptr,
|
|
|
|
};
|
|
|
|
vkQueueSubmit(context.graphics_queue, 1, &submit_info, nullptr);
|
|
|
|
vkQueueWaitIdle(context.graphics_queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
int VulkanImage::get_dma_buf_fd()
|
|
|
|
{
|
|
|
|
VkMemoryGetFdInfoKHR get_fd_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.memory = memory,
|
|
|
|
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
|
|
|
|
};
|
|
|
|
int fd = -1;
|
|
|
|
VkResult result = context.ext_procs.get_memory_fd(context.logical_device, &get_fd_info, &fd);
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
dbgln("vkGetMemoryFdKHR returned {}", to_underlying(result));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<NonnullRefPtr<VulkanImage>> create_shared_vulkan_image(VulkanContext const& context, uint32_t width, uint32_t height, VkFormat format, uint32_t num_modifiers, uint64_t const* modifiers)
|
|
|
|
{
|
|
|
|
VkDrmFormatModifierPropertiesListEXT format_mod_props_list = {};
|
|
|
|
format_mod_props_list.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
|
|
|
|
format_mod_props_list.pNext = nullptr;
|
|
|
|
VkFormatProperties2 format_props = {};
|
|
|
|
format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
|
|
|
|
format_props.pNext = &format_mod_props_list;
|
|
|
|
vkGetPhysicalDeviceFormatProperties2(context.physical_device, format, &format_props);
|
|
|
|
Vector<VkDrmFormatModifierPropertiesEXT> format_mod_props;
|
|
|
|
format_mod_props.resize(format_mod_props_list.drmFormatModifierCount);
|
|
|
|
format_mod_props_list.pDrmFormatModifierProperties = format_mod_props.data();
|
|
|
|
vkGetPhysicalDeviceFormatProperties2(context.physical_device, format, &format_props);
|
|
|
|
|
|
|
|
// populate a list of all format modifiers that are both renderable and accepted by the caller
|
|
|
|
Vector<uint64_t> format_mods;
|
|
|
|
for (VkDrmFormatModifierPropertiesEXT const& props : format_mod_props) {
|
|
|
|
if ((props.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) && (props.drmFormatModifierPlaneCount == 1)) {
|
|
|
|
for (uint32_t i = 0; i < num_modifiers; ++i) {
|
|
|
|
if (modifiers[i] == props.drmFormatModifier) {
|
|
|
|
format_mods.append(props.drmFormatModifier);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NonnullRefPtr<VulkanImage> image = make_ref_counted<VulkanImage>(context);
|
|
|
|
VkImageDrmFormatModifierListCreateInfoEXT image_drm_format_modifier_list_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.drmFormatModifierCount = static_cast<uint32_t>(format_mods.size()),
|
|
|
|
.pDrmFormatModifiers = format_mods.data(),
|
|
|
|
};
|
|
|
|
VkExternalMemoryImageCreateInfo external_mem_image_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
|
|
|
.pNext = &image_drm_format_modifier_list_info,
|
|
|
|
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
|
|
|
|
};
|
|
|
|
uint32_t queue_families[] = { context.graphics_queue_family, VK_QUEUE_FAMILY_EXTERNAL };
|
|
|
|
VkImageCreateInfo image_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
|
|
.pNext = &external_mem_image_info,
|
|
|
|
.flags = 0,
|
|
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
|
|
|
.format = format,
|
|
|
|
.extent = {
|
|
|
|
.width = width,
|
|
|
|
.height = height,
|
|
|
|
.depth = 1,
|
|
|
|
},
|
|
|
|
.mipLevels = 1,
|
|
|
|
.arrayLayers = 1,
|
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
|
|
|
|
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
|
|
|
.sharingMode = VK_SHARING_MODE_CONCURRENT,
|
2025-08-19 17:27:26 +02:00
|
|
|
.queueFamilyIndexCount = array_size(queue_families),
|
2025-08-14 19:00:44 -04:00
|
|
|
.pQueueFamilyIndices = queue_families,
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
};
|
|
|
|
auto result = vkCreateImage(context.logical_device, &image_info, nullptr, &image->image);
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
dbgln("vkCreateImage returned {}", to_underlying(result));
|
|
|
|
return Error::from_string_literal("image creation failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
VkMemoryRequirements mem_reqs;
|
|
|
|
vkGetImageMemoryRequirements(context.logical_device, image->image, &mem_reqs);
|
|
|
|
VkPhysicalDeviceMemoryProperties mem_props;
|
|
|
|
vkGetPhysicalDeviceMemoryProperties(context.physical_device, &mem_props);
|
|
|
|
uint32_t mem_type_idx;
|
|
|
|
for (mem_type_idx = 0; mem_type_idx < mem_props.memoryTypeCount; ++mem_type_idx) {
|
|
|
|
if ((mem_reqs.memoryTypeBits & (1 << mem_type_idx)) && (mem_props.memoryTypes[mem_type_idx].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mem_type_idx == mem_props.memoryTypeCount) {
|
|
|
|
return Error::from_string_literal("unable to find suitable image memory type");
|
|
|
|
}
|
|
|
|
|
|
|
|
VkExportMemoryAllocateInfo export_mem_alloc_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
|
|
|
|
};
|
|
|
|
VkMemoryAllocateInfo mem_alloc_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
|
|
.pNext = &export_mem_alloc_info,
|
|
|
|
.allocationSize = mem_reqs.size,
|
|
|
|
.memoryTypeIndex = mem_type_idx,
|
|
|
|
};
|
|
|
|
result = vkAllocateMemory(context.logical_device, &mem_alloc_info, nullptr, &image->memory);
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
dbgln("vkAllocateMemory returned {}", to_underlying(result));
|
|
|
|
return Error::from_string_literal("image memory allocation failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
result = vkBindImageMemory(context.logical_device, image->image, image->memory, 0);
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
dbgln("vkBindImageMemory returned {}", to_underlying(result));
|
|
|
|
return Error::from_string_literal("bind image memory failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
VkImageSubresource subresource = { VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT, 0, 0 };
|
|
|
|
VkSubresourceLayout subresource_layout = {};
|
|
|
|
vkGetImageSubresourceLayout(context.logical_device, image->image, &subresource, &subresource_layout);
|
|
|
|
|
|
|
|
VkImageDrmFormatModifierPropertiesEXT image_format_mod_props = {};
|
|
|
|
image_format_mod_props.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT;
|
|
|
|
image_format_mod_props.pNext = nullptr;
|
|
|
|
result = context.ext_procs.get_image_drm_format_modifier_properties(context.logical_device, image->image, &image_format_mod_props);
|
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
dbgln("vkGetImageDrmFormatModifierPropertiesEXT returned {}", to_underlying(result));
|
|
|
|
return Error::from_string_literal("image format modifier retrieval failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
// external APIs require general layout
|
|
|
|
VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL;
|
|
|
|
image->transition_layout(VK_IMAGE_LAYOUT_UNDEFINED, layout);
|
|
|
|
|
|
|
|
image->info = {
|
|
|
|
.format = image_info.format,
|
|
|
|
.extent = image_info.extent,
|
|
|
|
.tiling = image_info.tiling,
|
|
|
|
.usage = image_info.usage,
|
|
|
|
.sharing_mode = image_info.sharingMode,
|
|
|
|
.layout = layout,
|
|
|
|
.row_pitch = subresource_layout.rowPitch,
|
|
|
|
.modifier = image_format_mod_props.drmFormatModifier,
|
2024-07-03 19:23:27 +02:00
|
|
|
};
|
2025-08-14 19:00:44 -04:00
|
|
|
return image;
|
2024-07-03 19:23:27 +02:00
|
|
|
}
|
2025-08-19 12:07:03 -04:00
|
|
|
#endif
|
2024-07-03 19:23:27 +02:00
|
|
|
|
|
|
|
}
|