From 926cd66fcdd55ddb7c09a7a8ce65c6c2ac5741b7 Mon Sep 17 00:00:00 2001 From: Iason Paraskevopoulos Date: Fri, 12 Mar 2021 14:19:59 +0000 Subject: [PATCH] Add support for multiplane swapchain images in Wayland Updates wsialloc and wsi::wayland::swapchain to support multiplane image allocations. Uses the custom allocator for allocations in Wayland image creation. Change-Id: I1950b14b75711a76521bbf1967c3c835d006f8a8 Signed-off-by: Iason Paraskevopoulos --- layer/private_data.hpp | 6 +- util/wsialloc/wsialloc_ion.c | 40 ++-- wsi/headless/swapchain.cpp | 4 +- wsi/headless/swapchain.hpp | 6 +- wsi/swapchain_base.hpp | 6 +- wsi/wayland/swapchain.cpp | 378 +++++++++++++++++++++++++---------- wsi/wayland/swapchain.hpp | 46 ++++- 7 files changed, 354 insertions(+), 132 deletions(-) diff --git a/layer/private_data.hpp b/layer/private_data.hpp index b5b860c..0d8a252 100644 --- a/layer/private_data.hpp +++ b/layer/private_data.hpp @@ -55,7 +55,8 @@ namespace layer OPTIONAL(GetPhysicalDeviceSurfaceFormatsKHR) \ OPTIONAL(GetPhysicalDeviceSurfacePresentModesKHR) \ OPTIONAL(GetPhysicalDeviceSurfaceSupportKHR) \ - OPTIONAL(GetPhysicalDeviceImageFormatProperties2KHR) + OPTIONAL(GetPhysicalDeviceImageFormatProperties2KHR) \ + OPTIONAL(GetPhysicalDeviceFormatProperties2KHR) struct instance_dispatch_table { @@ -102,7 +103,8 @@ struct instance_dispatch_table OPTIONAL(GetSwapchainImagesKHR) \ OPTIONAL(AcquireNextImageKHR) \ OPTIONAL(QueuePresentKHR) \ - OPTIONAL(GetMemoryFdPropertiesKHR) + OPTIONAL(GetMemoryFdPropertiesKHR) \ + OPTIONAL(BindImageMemory2KHR) struct device_dispatch_table { diff --git a/util/wsialloc/wsialloc_ion.c b/util/wsialloc/wsialloc_ion.c index f403bf9..e0e32c8 100644 --- a/util/wsialloc/wsialloc_ion.c +++ b/util/wsialloc/wsialloc_ion.c @@ -42,7 +42,8 @@ /** Default alignment */ #define WSIALLOCP_MIN_ALIGN_SZ (64u) -struct ion_allocator { +struct ion_allocator +{ /* File descriptor of /dev/ion. */ int fd; /* Allocator heap id. */ @@ -221,43 +222,44 @@ int wsialloc_alloc( assert(new_fd != NULL); assert(offset != NULL); - int ret = 0; struct ion_allocator *ion = allocator->ptr; - if(modifier != NULL && *modifier != 0) + if (modifier != NULL && *modifier != 0) { return -ENOTSUP; } - size_t size = 0; - /* Validate format and determine per-plane bits per pixel. */ uint32_t nr_planes, bits_per_pixel[WSIALLOCP_MAX_PLANES]; - ret = wsiallocp_get_fmt_info(fourcc, &nr_planes, bits_per_pixel); + int ret = wsiallocp_get_fmt_info(fourcc, &nr_planes, bits_per_pixel); if (ret != 0) { return ret; } - /* Only single plane formats supported. */ - if (nr_planes != 1) + size_t size = 0; + for (uint32_t plane = 0; plane < nr_planes; plane++) { - return -ENOTSUP; + offset[plane] = size; + + /* Assumes multiple of 8--rework otherwise. */ + const uint32_t plane_bytes_per_pixel = bits_per_pixel[plane] / 8; + assert(plane_bytes_per_pixel * 8 == bits_per_pixel[plane]); + + stride[plane] = round_size_up_to_align(width * plane_bytes_per_pixel); + size += stride[plane] * height; } - /* Assumes multiple of 8--rework otherwise. */ - uint32_t plane0_bytes_per_pixel = bits_per_pixel[0] / 8; - assert(plane0_bytes_per_pixel * 8 == bits_per_pixel[0]); - - *stride = round_size_up_to_align(width * plane0_bytes_per_pixel); - size = *stride * height; - - *new_fd = allocate(ion->fd, size, ion->alloc_heap_id); - if (*new_fd < 0) + new_fd[0] = allocate(ion->fd, size, ion->alloc_heap_id); + if (new_fd[0] < 0) { return -errno; } - *offset = 0; + for (uint32_t plane = 1; plane < nr_planes; plane++) + { + new_fd[plane] = new_fd[0]; + } + return 0; } diff --git a/wsi/headless/swapchain.cpp b/wsi/headless/swapchain.cpp index 03af79b..fdf9627 100644 --- a/wsi/headless/swapchain.cpp +++ b/wsi/headless/swapchain.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020 Arm Limited. + * Copyright (c) 2017-2021 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -57,7 +57,7 @@ swapchain::~swapchain() teardown(); } -VkResult swapchain::create_image(const VkImageCreateInfo &image_create, wsi::swapchain_image &image) +VkResult swapchain::create_image(VkImageCreateInfo image_create, wsi::swapchain_image &image) { VkResult res = VK_SUCCESS; res = m_device_data.disp.CreateImage(m_device, &image_create, nullptr, &image.image); diff --git a/wsi/headless/swapchain.hpp b/wsi/headless/swapchain.hpp index c25d5c7..e4440ae 100644 --- a/wsi/headless/swapchain.hpp +++ b/wsi/headless/swapchain.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Arm Limited. + * Copyright (c) 2017-2019, 2021 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -72,7 +72,7 @@ protected: * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_INITIALIZATION_FAILED * depending on the error that occured. */ - VkResult create_image(const VkImageCreateInfo &image_create_info, wsi::swapchain_image &image); + VkResult create_image(VkImageCreateInfo image_create_info, wsi::swapchain_image &image); /** * @brief Method to perform a present - just calls unpresent_image on headless @@ -87,7 +87,7 @@ protected: * * @param image Handle to the image about to be released. */ - void destroy_image(wsi::swapchain_image &image); + void destroy_image(wsi::swapchain_image &image); }; } /* namespace headless */ diff --git a/wsi/swapchain_base.hpp b/wsi/swapchain_base.hpp index ccd5270..2cff142 100644 --- a/wsi/swapchain_base.hpp +++ b/wsi/swapchain_base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020 Arm Limited. + * Copyright (c) 2017-2021 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -306,7 +306,7 @@ protected: * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_INITIALIZATION_FAILED * depending on the error that occured. */ - virtual VkResult create_image(const VkImageCreateInfo &image_create_info, swapchain_image &image) = 0; + virtual VkResult create_image(VkImageCreateInfo image_create_info, swapchain_image &image) = 0; /** * @brief Method to present and image @@ -364,7 +364,7 @@ private: /** * @brief Per swapchain thread function that handles page flipping. - * + * * This thread should be running for the lifetime of the swapchain. * The thread simply calls the implementation's present_image() method. * There are 3 main cases we cover here: diff --git a/wsi/wayland/swapchain.cpp b/wsi/wayland/swapchain.cpp index 7a62de7..a2435af 100644 --- a/wsi/wayland/swapchain.cpp +++ b/wsi/wayland/swapchain.cpp @@ -27,6 +27,7 @@ #include "swapchain.hpp" #include "wl_helpers.hpp" +#include #include #include #include @@ -34,9 +35,12 @@ #include #include #include +#include #include "util/drm/drm_utils.hpp" +#define MAX_PLANES 4 + namespace wsi { namespace wayland @@ -60,14 +64,23 @@ make_proxy_with_queue(T *object, wl_event_queue *queue) return std::unique_ptr>(proxy, delete_proxy); } +const VkImageAspectFlagBits plane_flag_bits[MAX_PLANES] = { + VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT, + VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT, + VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT, + VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT, +}; + struct swapchain::wayland_image_data { - int buffer_fd; - int stride; - uint32_t offset; + int buffer_fd[MAX_PLANES]; + int stride[MAX_PLANES]; + uint32_t offset[MAX_PLANES]; wl_buffer *buffer; - VkDeviceMemory memory; + VkDeviceMemory memory[MAX_PLANES]; + + uint32_t num_planes; }; swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator) @@ -136,7 +149,7 @@ VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKH return VK_ERROR_INITIALIZATION_FAILED; } - auto registry = registry_owner{wl_display_get_registry(display_proxy.get())}; + auto registry = registry_owner{ wl_display_get_registry(display_proxy.get()) }; if (registry == nullptr) { WSI_PRINT_ERROR("Failed to get wl display registry.\n"); @@ -173,17 +186,18 @@ VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKH return VK_SUCCESS; } -static void create_succeeded(void *data, struct zwp_linux_buffer_params_v1 *params, struct wl_buffer *buffer) +extern "C" void create_succeeded(void *data, struct zwp_linux_buffer_params_v1 *params, + struct wl_buffer *buffer) { - struct wl_buffer **wayland_buffer = (struct wl_buffer **)data; + auto wayland_buffer = reinterpret_cast(data); *wayland_buffer = buffer; } static const struct zwp_linux_buffer_params_v1_listener params_listener = { create_succeeded, NULL }; -static void buffer_release(void *data, struct wl_buffer *wayl_buffer) +extern "C" void buffer_release(void *data, struct wl_buffer *wayl_buffer) { - swapchain *sc = (swapchain *)data; + auto sc = reinterpret_cast(data); sc->release_buffer(wayl_buffer); } @@ -192,8 +206,7 @@ void swapchain::release_buffer(struct wl_buffer *wayl_buffer) uint32_t i; for (i = 0; i < m_swapchain_images.size(); i++) { - wayland_image_data *data; - data = (wayland_image_data *)m_swapchain_images[i].data; + auto data = reinterpret_cast(m_swapchain_images[i].data); if (data->buffer == wayl_buffer) { unpresent_image(i); @@ -207,14 +220,145 @@ void swapchain::release_buffer(struct wl_buffer *wayl_buffer) static struct wl_buffer_listener buffer_listener = { buffer_release }; -VkResult swapchain::allocate_image(const VkImageCreateInfo &image_create_info, wayland_image_data *image_data, +VkResult swapchain::allocate_plane_memory(int fd, VkDeviceMemory *memory) +{ + uint32_t mem_index = -1; + VkResult result = get_fd_mem_type_index(fd, mem_index); + if (result != VK_SUCCESS) + { + return result; + } + + const off_t dma_buf_size = lseek(fd, 0, SEEK_END); + if (dma_buf_size < 0) + { + WSI_PRINT_ERROR("Failed to get DMA Buf size.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + VkImportMemoryFdInfoKHR import_mem_info = {}; + import_mem_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + import_mem_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + import_mem_info.fd = fd; + + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &import_mem_info; + alloc_info.allocationSize = static_cast(dma_buf_size); + alloc_info.memoryTypeIndex = mem_index; + + result = m_device_data.disp.AllocateMemory( + m_device, &alloc_info, get_allocation_callbacks(), memory); + + if (result != VK_SUCCESS) + { + WSI_PRINT_ERROR("Failed to import memory.\n"); + return result; + } + + return VK_SUCCESS; +} + +VkResult swapchain::get_fd_mem_type_index(int fd, uint32_t &mem_idx) +{ + VkMemoryFdPropertiesKHR mem_props = {}; + mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR; + + VkResult result = m_device_data.disp.GetMemoryFdPropertiesKHR( + m_device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, fd, &mem_props); + if (result != VK_SUCCESS) + { + WSI_PRINT_ERROR("Error querying Fd properties.\n"); + return result; + } + + for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++) + { + if (mem_props.memoryTypeBits & (1 << mem_idx)) + { + break; + } + } + + assert(mem_idx < VK_MAX_MEMORY_TYPES); + + return VK_SUCCESS; +} + +VkResult swapchain::get_drm_format_properties( + VkFormat format, util::vector &format_props_list) +{ + VkDrmFormatModifierPropertiesListEXT format_modifier_props = {}; + format_modifier_props.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT; + + VkFormatProperties2KHR format_props = {}; + format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR; + format_props.pNext = &format_modifier_props; + + m_device_data.instance_data.disp.GetPhysicalDeviceFormatProperties2KHR( + m_device_data.physical_device, format, &format_props); + + if (!format_props_list.try_resize(format_modifier_props.drmFormatModifierCount)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + format_modifier_props.pDrmFormatModifierProperties = format_props_list.data(); + m_device_data.instance_data.disp.GetPhysicalDeviceFormatProperties2KHR( + m_device_data.physical_device, format, &format_props); + + return VK_SUCCESS; +} + +static bool is_disjoint_supported( + const util::vector &format_props, uint64_t modifier) +{ + for (const auto &prop : format_props) + { + if (prop.drmFormatModifier == modifier && + prop.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT) + { + return true; + } + } + + return false; +} + +static uint32_t get_same_fd_index(int fd, int const *fds) +{ + uint32_t index = 0; + while (fd != fds[index]) + { + index++; + } + + return index; +} + +VkResult swapchain::allocate_image(VkImageCreateInfo &image_create_info, wayland_image_data *image_data, VkImage *image) { VkResult result = VK_SUCCESS; + const uint64_t modifier = DRM_FORMAT_MOD_LINEAR; image_data->buffer = nullptr; - image_data->buffer_fd = -1; - image_data->memory = VK_NULL_HANDLE; + image_data->num_planes = 0; + for (uint32_t plane = 0; plane < MAX_PLANES; plane++) + { + image_data->buffer_fd[plane] = -1; + image_data->memory[plane] = VK_NULL_HANDLE; + } + + /* Query support for disjoint images. */ + util::vector drm_format_props(m_allocator); + result = get_drm_format_properties(image_create_info.format, drm_format_props); + if (result != VK_SUCCESS) + { + WSI_PRINT_ERROR("Failed to get format properties.\n"); + return result; + } + auto is_disjoint = is_disjoint_supported(drm_format_props, modifier); VkExternalImageFormatPropertiesKHR external_props = {}; external_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR; @@ -230,7 +374,7 @@ VkResult swapchain::allocate_image(const VkImageCreateInfo &image_create_info, w VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_mod_info = {}; drm_mod_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT; drm_mod_info.pNext = &external_info; - drm_mod_info.drmFormatModifier = DRM_FORMAT_MOD_LINEAR; + drm_mod_info.drmFormatModifier = modifier; drm_mod_info.sharingMode = image_create_info.sharingMode; drm_mod_info.queueFamilyIndexCount = image_create_info.queueFamilyIndexCount; drm_mod_info.pQueueFamilyIndices = image_create_info.pQueueFamilyIndices; @@ -284,27 +428,51 @@ VkResult swapchain::allocate_image(const VkImageCreateInfo &image_create_info, w else { /* TODO: Handle Dedicated allocation bit. */ - uint32_t fourcc = util::drm::vk_to_drm_format(image_create_info.format); + const auto fourcc = util::drm::vk_to_drm_format(image_create_info.format); - int res = + const auto res = wsialloc_alloc(&m_wsi_allocator, fourcc, image_create_info.extent.width, image_create_info.extent.height, - &image_data->stride, &image_data->buffer_fd, &image_data->offset, nullptr); + image_data->stride, image_data->buffer_fd, image_data->offset, nullptr); if (res != 0) { WSI_PRINT_ERROR("Failed allocation of DMA Buffer.\n"); return VK_ERROR_OUT_OF_HOST_MEMORY; } + + for (uint32_t plane = 0; plane < MAX_PLANES; plane++) { - assert(image_data->stride >= 0); - VkSubresourceLayout image_layout = {}; - image_layout.offset = image_data->offset; - image_layout.rowPitch = static_cast(image_data->stride); + if (image_data->buffer_fd[plane] == -1) + { + break; + } + image_data->num_planes++; + } + + { + util::vector image_layout(m_allocator); + if (!image_layout.try_resize(image_data->num_planes)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (uint32_t plane = 0; plane < image_data->num_planes; plane++) + { + assert(image_data->stride[plane] >= 0); + image_layout[plane].offset = image_data->offset[plane]; + image_layout[plane].rowPitch = static_cast(image_data->stride[plane]); + } + + if (is_disjoint) + { + image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT; + } + VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info = {}; drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT; drm_mod_info.pNext = image_create_info.pNext; drm_mod_info.drmFormatModifier = DRM_FORMAT_MOD_LINEAR; - drm_mod_info.drmFormatModifierPlaneCount = 1; - drm_mod_info.pPlaneLayouts = &image_layout; + drm_mod_info.drmFormatModifierPlaneCount = image_data->num_planes; + drm_mod_info.pPlaneLayouts = image_layout.data(); VkExternalMemoryImageCreateInfoKHR external_info = {}; external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR; @@ -322,88 +490,87 @@ VkResult swapchain::allocate_image(const VkImageCreateInfo &image_create_info, w return result; } { - VkMemoryFdPropertiesKHR mem_props = {}; - mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR; - - result = m_device_data.disp.GetMemoryFdPropertiesKHR(m_device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - image_data->buffer_fd, &mem_props); - if (result != VK_SUCCESS) + if (is_disjoint) { - WSI_PRINT_ERROR("Error querying Fd properties.\n"); - return result; - } - - uint32_t mem_idx; - for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++) - { - if (mem_props.memoryTypeBits & (1 << mem_idx)) + util::vector bind_img_mem_infos(m_allocator); + if (!bind_img_mem_infos.try_resize(image_data->num_planes)) { - break; + return VK_ERROR_OUT_OF_HOST_MEMORY; } + + util::vector bind_plane_mem_infos(m_allocator); + if (!bind_plane_mem_infos.try_resize(image_data->num_planes)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (uint32_t plane = 0; plane < image_data->num_planes; plane++) + { + const auto fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd); + if (fd_index == plane) + { + result = allocate_plane_memory(image_data->buffer_fd[plane], &image_data->memory[fd_index]); + if (result != VK_SUCCESS) + { + return result; + } + } + + bind_plane_mem_infos[plane].planeAspect = plane_flag_bits[plane]; + bind_plane_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; + bind_plane_mem_infos[plane].pNext = NULL; + + bind_img_mem_infos[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; + bind_img_mem_infos[plane].pNext = &bind_plane_mem_infos[plane]; + bind_img_mem_infos[plane].image = *image; + bind_img_mem_infos[plane].memory = image_data->memory[fd_index]; + } + + result = m_device_data.disp.BindImageMemory2KHR(m_device, bind_img_mem_infos.size(), + bind_img_mem_infos.data()); } - off_t dma_buf_size = lseek(image_data->buffer_fd, 0, SEEK_END); - if (dma_buf_size < 0) + else { - WSI_PRINT_ERROR("Failed to get DMA Buf size.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; + /* Make sure one fd has been allocated. */ + for (uint32_t plane = 1; plane < image_data->num_planes; plane++) + { + if (image_data->buffer_fd[plane] != image_data->buffer_fd[0]) + { + WSI_PRINT_ERROR("Different fds per plane for a non disjoint image.\n"); + return VK_ERROR_INITIALIZATION_FAILED; + } + } + + result = allocate_plane_memory(image_data->buffer_fd[0], &image_data->memory[0]); + if (result != VK_SUCCESS) + { + return result; + } + + result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory[0], 0); } - - VkImportMemoryFdInfoKHR import_mem_info = {}; - import_mem_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; - import_mem_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - import_mem_info.fd = image_data->buffer_fd; - - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.pNext = &import_mem_info; - alloc_info.allocationSize = static_cast(dma_buf_size); - alloc_info.memoryTypeIndex = mem_idx; - - result = m_device_data.disp.AllocateMemory(m_device, &alloc_info, get_allocation_callbacks(), &image_data->memory); } - if (result != VK_SUCCESS) - { - WSI_PRINT_ERROR("Failed to import memory.\n"); - return result; - } - result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory, 0); } return result; } -VkResult swapchain::create_image(const VkImageCreateInfo &image_create_info, swapchain_image &image) +VkResult swapchain::create_image(VkImageCreateInfo image_create_info, swapchain_image &image) { - uint32_t fourcc = util::drm::vk_to_drm_format(image_create_info.format); - - int res; - VkResult result = VK_SUCCESS; - - wayland_image_data *image_data = nullptr; - VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 }; - /* Create image_data */ - if (get_allocation_callbacks() != nullptr) - { - image_data = static_cast( - get_allocation_callbacks()->pfnAllocation(get_allocation_callbacks()->pUserData, sizeof(wayland_image_data), - alignof(wayland_image_data), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); - } - else - { - image_data = static_cast(malloc(sizeof(wayland_image_data))); - } + auto image_data = m_allocator.create(1); if (image_data == nullptr) { return VK_ERROR_OUT_OF_HOST_MEMORY; } - image.data = reinterpret_cast(image_data); + image.data = image_data; image.status = swapchain_image::FREE; - result = allocate_image(image_create_info, image_data, &image.image); + VkResult result = allocate_image(image_create_info, image_data, &image.image); if (result != VK_SUCCESS) { WSI_PRINT_ERROR("Failed to allocate image.\n"); + destroy_image(image); return result; } @@ -417,15 +584,22 @@ VkResult swapchain::create_image(const VkImageCreateInfo &image_create_info, swa } zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(dmabuf_interface_proxy.get()); - zwp_linux_buffer_params_v1_add(params, image_data->buffer_fd, 0, image_data->offset, image_data->stride, 0, 0); - res = zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, &image_data->buffer); + + for (uint32_t plane = 0; plane < image_data->num_planes; plane++) + { + zwp_linux_buffer_params_v1_add(params, image_data->buffer_fd[plane], plane, + image_data->offset[plane], image_data->stride[plane], 0, 0); + } + + auto res = zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, &image_data->buffer); if (res < 0) { destroy_image(image); return VK_ERROR_INITIALIZATION_FAILED; } - zwp_linux_buffer_params_v1_create(params, image_create_info.extent.width, image_create_info.extent.height, fourcc, - 0); + const auto fourcc = util::drm::vk_to_drm_format(image_create_info.format); + zwp_linux_buffer_params_v1_create(params, image_create_info.extent.width, + image_create_info.extent.height, fourcc, 0); /* TODO: don't roundtrip - we should be able to send the create request now, * and only wait for it on first present. only do this once, not for all buffers created */ @@ -448,6 +622,7 @@ VkResult swapchain::create_image(const VkImageCreateInfo &image_create_info, swa } /* Initialize presentation fence. */ + VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 }; result = m_device_data.disp.CreateFence(m_device, &fenceInfo, get_allocation_callbacks(), &image.present_fence); if (result != VK_SUCCESS) { @@ -571,23 +746,24 @@ void swapchain::destroy_image(swapchain_image &image) { wl_buffer_destroy(image_data->buffer); } - if (image_data->memory != VK_NULL_HANDLE) + + for (uint32_t plane = 0; plane < image_data->num_planes; plane++) { - m_device_data.disp.FreeMemory(m_device, image_data->memory, get_allocation_callbacks()); - } - else if (image_data->buffer_fd >= 0) - { - close(image_data->buffer_fd); + if (image_data->memory[plane] != VK_NULL_HANDLE) + { + m_device_data.disp.FreeMemory(m_device, image_data->memory[plane], get_allocation_callbacks()); + } + else if (image_data->buffer_fd[plane] >= 0) + { + const auto same_fd_index = get_same_fd_index(image_data->buffer_fd[plane], image_data->buffer_fd); + if (same_fd_index == plane) + { + close(image_data->buffer_fd[plane]); + } + } } - if (get_allocation_callbacks() != nullptr) - { - get_allocation_callbacks()->pfnFree(get_allocation_callbacks()->pUserData, image_data); - } - else - { - free(image_data); - } + m_allocator.destroy(1, image_data); image.data = nullptr; } diff --git a/wsi/wayland/swapchain.hpp b/wsi/wayland/swapchain.hpp index 59bac5c..66bd5f7 100644 --- a/wsi/wayland/swapchain.hpp +++ b/wsi/wayland/swapchain.hpp @@ -67,7 +67,7 @@ protected: * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_INITIALIZATION_FAILED * depending on the error that occurred. */ - VkResult create_image(const VkImageCreateInfo &image_create_info, swapchain_image &image) override; + VkResult create_image(VkImageCreateInfo image_create_info, swapchain_image &image) override; /** * @brief Method to present an image @@ -103,7 +103,8 @@ protected: private: struct wayland_image_data; - VkResult allocate_image(const VkImageCreateInfo &image_create_info, wayland_image_data *image_data, VkImage *image); + + VkResult allocate_image(VkImageCreateInfo &image_create_info, wayland_image_data *image_data, VkImage *image); struct wl_display *m_display; struct wl_surface *m_surface; @@ -126,6 +127,47 @@ private: * callback to indicate the server is ready for the next buffer. */ bool m_present_pending; + + /* + * @brief Allocate memory for an image plane. + * + * Allocates a VkDeviceMemory object from a given fd for an image plane. First + * it makes a call to get_fd_mem_type_index() to acquire the memory type for + * the given fd and then it allocates device memory by calling vkAllocateMemory(). + * + * @param fd The plane's fd. + * @param[out] memory The allocated VkDeviceMemory object. + * + * @return VK_SUCCESS on success. If one of the functions that are being called + * fails its return value is returned. VK_ERROR_OUT_OF_HOST_MEMORY is returned + * when the host gets out of memory. + */ + VkResult allocate_plane_memory(int fd, VkDeviceMemory *memory); + + /* + * @brief Get the memory type which the specified file descriptor can be + * imported as. + * + * @param fd The given fd. + * @param[out] mem_idx The index of the supported memory type. + * + * @return VK_SUCCESS on success. On failure the error value of + * vkGetMemoryFdPropertiesKHR is returned. + */ + VkResult get_fd_mem_type_index(int fd, uint32_t &mem_idx); + + /* + * @brief Get the properties a format has when combined with a DRM modifier. + * + * @param format The target format. + * @param[out] format_props_list A vector which will store the supported properties + * for every modifier. + * + * @return VK_SUCCESS on success. VK_ERROR_OUT_OF_HOST_MEMORY is returned when + * the host gets out of memory. + */ + VkResult get_drm_format_properties( + VkFormat format, util::vector &format_props_list); }; } // namespace wayland } // namespace wsi