From ca3820a0bad27e2e367d35c588309f2a54976323 Mon Sep 17 00:00:00 2001 From: Iason Paraskevopoulos Date: Thu, 27 Mar 2025 18:06:44 +0000 Subject: [PATCH] Add external memory extension Adds a swapchain create info extension for creating an image using external memory. This removes the need for modifying the image_create_info in the display and wayland backends. There is still code duplication left in these backends though, because swapchain allocation needs to know the selected format. This will be removed when the swapchain images will be created from the swapchain image creator. Moves the definition of drm_format_pair to drm_utils. Removes two step initialization from swapchain_wsi_allocator. Change-Id: I0c937a59cc62e7e3134f0af4728fdda3739237bd Signed-off-by: Iason Paraskevopoulos --- CMakeLists.txt | 6 +- util/drm/drm_utils.hpp | 11 +- wsi/display/drm_display.cpp | 19 +- wsi/display/drm_display.hpp | 10 +- wsi/display/swapchain.cpp | 69 ++--- wsi/display/swapchain.hpp | 2 +- wsi/surface.hpp | 11 +- .../external_memory_extension.cpp | 235 ++++++++++++++++++ .../external_memory_extension.hpp | 89 +++++++ wsi/wayland/surface.cpp | 6 +- wsi/wayland/surface.hpp | 8 +- wsi/wayland/surface_properties.cpp | 12 +- wsi/wayland/swapchain.cpp | 59 ++--- wsi/wayland/swapchain.hpp | 2 +- wsi/wsi_alloc_utils.cpp | 9 +- wsi/wsi_alloc_utils.hpp | 33 ++- 16 files changed, 463 insertions(+), 118 deletions(-) create mode 100644 wsi/swapchain_image_create_extensions/external_memory_extension.cpp create mode 100644 wsi/swapchain_image_create_extensions/external_memory_extension.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b0b8f5..85845b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,7 +145,8 @@ if(BUILD_WSI_WAYLAND) wsi/wayland/surface_properties.cpp wsi/wayland/surface.cpp wsi/wayland/wl_helpers.cpp - wsi/wayland/swapchain.cpp) + wsi/wayland/swapchain.cpp + wsi/swapchain_image_create_extensions/external_memory_extension.cpp) if(VULKAN_WSI_LAYER_EXPERIMENTAL) target_sources(wayland_wsi PRIVATE wsi/wayland/present_timing_handler.cpp) @@ -249,7 +250,8 @@ if (BUILD_WSI_DISPLAY) wsi/display/drm_display.cpp wsi/display/surface_properties.cpp wsi/display/swapchain.cpp - wsi/display/surface.cpp) + wsi/display/surface.cpp + wsi/swapchain_image_create_extensions/external_memory_extension.cpp) pkg_check_modules(LIBDRM REQUIRED libdrm) message(STATUS "Using libdrm include directories: ${LIBDRM_INCLUDE_DIRS}") diff --git a/util/drm/drm_utils.hpp b/util/drm/drm_utils.hpp index 4ec9edf..9e6fe2e 100644 --- a/util/drm/drm_utils.hpp +++ b/util/drm/drm_utils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021-2022, 2024 Arm Limited. + * Copyright (c) 2019-2025 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -31,6 +31,15 @@ namespace util namespace drm { +/** + * @brief Struct describing a DRM format with modifier. + */ +struct drm_format_pair +{ + uint32_t fourcc; + uint64_t modifier; +}; + uint32_t vk_to_drm_format(VkFormat vk_format); VkFormat drm_to_vk_format(uint32_t drm_format); VkFormat drm_to_vk_srgb_format(uint32_t drm_format); diff --git a/wsi/display/drm_display.cpp b/wsi/display/drm_display.cpp index 193a3d4..acbc3d5 100644 --- a/wsi/display/drm_display.cpp +++ b/wsi/display/drm_display.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Arm Limited. + * Copyright (c) 2024-2025 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -44,7 +44,7 @@ namespace display const std::string default_dri_device_name{ "/dev/dri/card0" }; drm_display::drm_display(util::fd_owner drm_fd, int crtc_id, drm_connector_owner drm_connector, - util::unique_ptr> supported_formats, + util::unique_ptr> supported_formats, util::unique_ptr display_modes, size_t num_display_modes, uint32_t max_width, uint32_t max_height, bool supports_fb_modifiers) : m_drm_fd(std::move(drm_fd)) @@ -147,11 +147,12 @@ static bool find_primary_plane(const util::fd_owner &drm_fd, const drm_plane_res } static bool fill_supported_formats(const drm_plane_owner &primary_plane, - util::vector &supported_formats) + util::vector &supported_formats) { for (uint32_t i = 0; i < primary_plane->count_formats; i++) { - if (!supported_formats.try_push_back(drm_format_pair{ primary_plane->formats[i], DRM_FORMAT_MOD_LINEAR })) + if (!supported_formats.try_push_back( + util::drm::drm_format_pair{ primary_plane->formats[i], DRM_FORMAT_MOD_LINEAR })) { WSI_LOG_ERROR("Out of host memory."); return false; @@ -163,7 +164,7 @@ static bool fill_supported_formats(const drm_plane_owner &primary_plane, static bool fill_supported_formats_with_modifiers(uint32_t primary_plane_index, const util::fd_owner &drm_fd, const drm_plane_resources_owner &plane_res, - util::vector &supported_formats) + util::vector &supported_formats) { drm_object_properties_owner object_properties{ drmModeObjectGetProperties( drm_fd.get(), plane_res->planes[primary_plane_index], DRM_MODE_OBJECT_PLANE) }; @@ -191,7 +192,7 @@ static bool fill_supported_formats_with_modifiers(uint32_t primary_plane_index, while (drmModeFormatModifierBlobIterNext(blob.get(), &iter)) { - if (!supported_formats.try_push_back(drm_format_pair{ iter.fmt, iter.mod })) + if (!supported_formats.try_push_back(util::drm::drm_format_pair{ iter.fmt, iter.mod })) { return false; } @@ -317,7 +318,7 @@ std::optional drm_display::make_display(const util::allocator &allo } #endif - auto supported_formats = allocator.make_unique>(allocator); + auto supported_formats = allocator.make_unique>(allocator); if (supports_fb_modifiers) { @@ -365,12 +366,12 @@ std::optional &drm_display::get_display() return display; } -const util::vector *drm_display::get_supported_formats() const +const util::vector *drm_display::get_supported_formats() const { return m_supported_formats.get(); } -bool drm_display::is_format_supported(const drm_format_pair &format) const +bool drm_display::is_format_supported(const util::drm::drm_format_pair &format) const { auto supported_format = std::find_if(m_supported_formats->begin(), m_supported_formats->end(), [format](const auto &supported_format) { diff --git a/wsi/display/drm_display.hpp b/wsi/display/drm_display.hpp index 0982d4e..d1b313f 100644 --- a/wsi/display/drm_display.hpp +++ b/wsi/display/drm_display.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Arm Limited. + * Copyright (c) 2024-2025 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -256,7 +256,7 @@ public: * * @return Pointer to vector of supported formats. */ - const util::vector *get_supported_formats() const; + const util::vector *get_supported_formats() const; /** * @brief Query the display for support for adding framebuffers with format modifiers. @@ -271,7 +271,7 @@ public: * @param format The format to query support for. * @return true if the format is supported by the display, otherwise false. */ - bool is_format_supported(const drm_format_pair &format) const; + bool is_format_supported(const util::drm::drm_format_pair &format) const; /** * @brief Returns a CRTC compatible with this display's connector. @@ -297,7 +297,7 @@ private: * @param allocator The allocator that the display will use. */ drm_display(util::fd_owner drm_fd, int crtc_id, drm_connector_owner drm_connector, - util::unique_ptr> supported_formats, + util::unique_ptr> supported_formats, util::unique_ptr display_modes, size_t num_display_modes, uint32_t max_width, uint32_t max_height, bool supports_fb_modifiers); @@ -319,7 +319,7 @@ private: /** * @brief Vector of supported formats for use with the display. */ - util::unique_ptr> m_supported_formats; + util::unique_ptr> m_supported_formats; /** * @brief Pointer to available display modes for the connected display. diff --git a/wsi/display/swapchain.cpp b/wsi/display/swapchain.cpp index a14e430..6a81d95 100644 --- a/wsi/display/swapchain.cpp +++ b/wsi/display/swapchain.cpp @@ -39,6 +39,8 @@ #include "swapchain.hpp" +#include + namespace wsi { @@ -48,7 +50,7 @@ namespace display swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator, surface &wsi_surface) : wsi::swapchain_base(dev_data, pAllocator) - , m_wsi_allocator() + , m_wsi_allocator(nullptr) , m_display_mode(wsi_surface.get_display_mode()) , m_image_creation_parameters({}, m_allocator, {}, {}) { @@ -108,7 +110,17 @@ VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKH UNUSED(swapchain_create_info); UNUSED(use_presentation_thread); - TRY(m_wsi_allocator.init()); + auto wsi_allocator = swapchain_wsialloc_allocator::create(); + if (!wsi_allocator.has_value()) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + + m_wsi_allocator = m_allocator.make_unique(std::move(*wsi_allocator)); + if (m_wsi_allocator == nullptr) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } return VK_SUCCESS; } @@ -139,7 +151,7 @@ VkResult swapchain::get_surface_compatible_formats(const VkImageCreateInfo &info for (const auto &prop : drm_format_props) { - drm_format_pair drm_format{ util::drm::vk_to_drm_format(info.format), prop.drmFormatModifier }; + util::drm::drm_format_pair drm_format{ util::drm::vk_to_drm_format(info.format), prop.drmFormatModifier }; if (!display->is_format_supported(drm_format)) { @@ -264,7 +276,7 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, disp allocation_params params = { (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0, image_create_info.extent, importable_formats, enable_fixed_rate, avoid_allocation }; wsialloc_allocate_result alloc_result = { {}, { 0 }, { 0 }, { -1 }, false }; - TRY(m_wsi_allocator.allocate(params, &alloc_result)); + TRY(m_wsi_allocator->allocate(params, &alloc_result)); *allocated_format = alloc_result.format; @@ -298,26 +310,6 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, disp return VK_SUCCESS; } -static VkResult fill_image_create_info(VkImageCreateInfo &image_create_info, - util::vector &image_plane_layouts, - VkImageDrmFormatModifierExplicitCreateInfoEXT &drm_mod_info, - VkExternalMemoryImageCreateInfoKHR &external_info, - display_image_data &image_data, uint64_t modifier) -{ - TRY_LOG_CALL(image_data.external_mem.fill_image_plane_layouts(image_plane_layouts)); - - if (image_data.external_mem.is_disjoint()) - { - image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT; - } - - image_data.external_mem.fill_drm_mod_info(image_create_info.pNext, drm_mod_info, image_plane_layouts, modifier); - image_data.external_mem.fill_external_info(external_info, &drm_mod_info); - image_create_info.pNext = &external_info; - image_create_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; - return VK_SUCCESS; -} - VkResult swapchain::allocate_image(display_image_data *image_data) { util::vector importable_formats(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); @@ -336,8 +328,8 @@ VkResult swapchain::create_framebuffer(const VkImageCreateInfo &image_create_inf VkResult ret_code = VK_SUCCESS; std::array strides{ 0, 0, 0, 0 }; std::array modifiers{ 0, 0, 0, 0 }; - const drm_format_pair allocated_format{ m_image_creation_parameters.m_allocated_format.fourcc, - m_image_creation_parameters.m_allocated_format.modifier }; + const util::drm::drm_format_pair allocated_format{ m_image_creation_parameters.m_allocated_format.fourcc, + m_image_creation_parameters.m_allocated_format.modifier }; auto &display = drm_display::get_display(); if (!display.has_value()) @@ -427,7 +419,7 @@ VkResult swapchain::create_swapchain_image(VkImageCreateInfo image_create_info, } image.data = image_data; - if (m_image_create_info.format == VK_FORMAT_UNDEFINED) + if (m_image_creation_parameters.m_allocated_format.fourcc == DRM_FORMAT_INVALID) { util::vector importable_formats( util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); @@ -459,11 +451,6 @@ VkResult swapchain::create_swapchain_image(VkImageCreateInfo image_create_info, } } - TRY_LOG_CALL(fill_image_create_info( - image_create_info, m_image_creation_parameters.m_image_layout, m_image_creation_parameters.m_drm_mod_info, - m_image_creation_parameters.m_external_info, *image_data, allocated_format.modifier)); - - m_image_create_info = image_create_info; m_image_creation_parameters.m_allocated_format = allocated_format; } @@ -640,8 +627,22 @@ VkResult swapchain::get_required_image_creator_extensions( const VkSwapchainCreateInfoKHR &swapchain_create_info, util::vector> *extensions) { - UNUSED(swapchain_create_info); - UNUSED(extensions); + auto compression_control = swapchain_image_create_compression_control::create( + m_device_data.is_swapchain_compression_control_enabled(), swapchain_create_info); + + auto &display = drm_display::get_display(); + if (!display.has_value()) + { + WSI_LOG_ERROR("DRM display not available."); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + if (!extensions->try_push_back(m_allocator.make_unique( + compression_control, m_wsi_allocator.get(), display->get_supported_formats(), m_device_data.physical_device, + m_allocator))) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } return VK_SUCCESS; } diff --git a/wsi/display/swapchain.hpp b/wsi/display/swapchain.hpp index 9b1daa7..5957dd8 100644 --- a/wsi/display/swapchain.hpp +++ b/wsi/display/swapchain.hpp @@ -146,7 +146,7 @@ private: */ VkResult add_required_extensions(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info) override; - swapchain_wsialloc_allocator m_wsi_allocator; + util::unique_ptr m_wsi_allocator; drm_display_mode *m_display_mode; image_creation_parameters m_image_creation_parameters; diff --git a/wsi/surface.hpp b/wsi/surface.hpp index 90ce1c9..bbdc666 100644 --- a/wsi/surface.hpp +++ b/wsi/surface.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024 Arm Limited. + * Copyright (c) 2021-2025 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -36,15 +36,6 @@ namespace wsi { -/** - * @brief Struct describing a DRM format with modifier. - */ -struct drm_format_pair -{ - uint32_t fourcc; - uint64_t modifier; -}; - /** * @brief A generic WSI representation of a VkSurface. * diff --git a/wsi/swapchain_image_create_extensions/external_memory_extension.cpp b/wsi/swapchain_image_create_extensions/external_memory_extension.cpp new file mode 100644 index 0000000..524c69f --- /dev/null +++ b/wsi/swapchain_image_create_extensions/external_memory_extension.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2025 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file external_memory_extension.cpp + */ +#include + +#include +#include + +#include + +#include "external_memory_extension.hpp" + +namespace wsi +{ + +VkResult swapchain_image_create_external_memory::extend_image_create_info(VkImageCreateInfo *image_create_info) +{ + assert(image_create_info != nullptr); + + util::vector importable_formats(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); + util::vector exportable_modifiers(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); + + /* Query supported modifers. */ + util::vector drm_format_props( + util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); + + TRY_LOG_CALL( + get_surface_compatible_formats(*image_create_info, importable_formats, exportable_modifiers, drm_format_props)); + + /* TODO: Handle exportable images which use ICD allocated memory in preference to an external allocator. */ + if (importable_formats.empty()) + { + WSI_LOG_ERROR("Export/Import not supported."); + return VK_ERROR_INITIALIZATION_FAILED; + } + + bool enable_fixed_rate = false; + if (m_compression) + { + if (m_compression->get_bitmask_for_image_compression_flags() & VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT) + { + enable_fixed_rate = true; + } + } + + allocation_params params = { (image_create_info->flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0, + image_create_info->extent, importable_formats, enable_fixed_rate, true }; + wsialloc_allocate_result alloc_result = { {}, { 0 }, { 0 }, { -1 }, false }; + assert(m_wsi_allocator); + TRY(m_wsi_allocator->allocate(params, &alloc_result)); + + uint32_t prop_plane_count = 0; + for (auto &prop : drm_format_props) + { + if (prop.drmFormatModifier == alloc_result.format.modifier) + { + prop_plane_count = prop.drmFormatModifierPlaneCount; + } + } + + if (alloc_result.is_disjoint) + { + image_create_info->flags |= VK_IMAGE_CREATE_DISJOINT_BIT; + } + + const uint32_t format_planes = util::drm::drm_fourcc_format_get_num_planes(alloc_result.format.fourcc); + if (!m_plane_layouts.try_resize(format_planes)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (uint32_t plane = 0; plane < format_planes; ++plane) + { + assert(alloc_result.average_row_strides[plane] >= 0); + m_plane_layouts[plane].offset = alloc_result.offsets[plane]; + m_plane_layouts[plane].rowPitch = static_cast(alloc_result.average_row_strides[plane]); + } + + m_drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT; + m_drm_mod_info.pNext = image_create_info->pNext; + m_drm_mod_info.drmFormatModifier = alloc_result.format.modifier; + m_drm_mod_info.drmFormatModifierPlaneCount = prop_plane_count; + m_drm_mod_info.pPlaneLayouts = m_plane_layouts.data(); + + m_external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR; + m_external_info.pNext = &m_drm_mod_info; + m_external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + + image_create_info->pNext = &m_external_info; + image_create_info->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; + + return VK_SUCCESS; +} + +VkResult swapchain_image_create_external_memory::get_surface_compatible_formats( + const VkImageCreateInfo &info, util::vector &importable_formats, + util::vector &exportable_modifers, util::vector &drm_format_props) +{ + TRY_LOG(util::get_drm_format_properties(m_physical_device, info.format, drm_format_props), + "Failed to get format properties"); + + for (const auto &prop : drm_format_props) + { + bool is_supported = true; + util::drm::drm_format_pair drm_format{ util::drm::vk_to_drm_format(info.format), prop.drmFormatModifier }; + + if (m_surface_formats != nullptr) + { + is_supported = false; + for (const auto &format : *m_surface_formats) + { + if (format.fourcc == drm_format.fourcc && format.modifier == drm_format.modifier) + { + is_supported = true; + break; + } + } + } + + if (!is_supported) + { + continue; + } + + VkExternalImageFormatPropertiesKHR external_props = {}; + external_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR; + + VkImageFormatProperties2KHR format_props = {}; + format_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR; + format_props.pNext = &external_props; + + VkResult result = VK_SUCCESS; + { + VkPhysicalDeviceExternalImageFormatInfoKHR external_info = {}; + external_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR; + external_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + + 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 = prop.drmFormatModifier; + drm_mod_info.sharingMode = info.sharingMode; + drm_mod_info.queueFamilyIndexCount = info.queueFamilyIndexCount; + drm_mod_info.pQueueFamilyIndices = info.pQueueFamilyIndices; + + VkPhysicalDeviceImageFormatInfo2KHR image_info = {}; + image_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR; + image_info.pNext = &drm_mod_info; + image_info.format = info.format; + image_info.type = info.imageType; + image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; + image_info.usage = info.usage; + image_info.flags = info.flags; + + VkImageCompressionControlEXT compression_control = {}; + if (m_compression) + { + compression_control = m_compression->get_compression_control_properties(); + compression_control.pNext = image_info.pNext; + image_info.pNext = &compression_control; + } + + auto &instance_data = layer::instance_private_data::get(m_physical_device); + result = instance_data.disp.GetPhysicalDeviceImageFormatProperties2KHR(m_physical_device, &image_info, + &format_props); + } + if (result != VK_SUCCESS) + { + continue; + } + if (format_props.imageFormatProperties.maxExtent.width < info.extent.width || + format_props.imageFormatProperties.maxExtent.height < info.extent.height || + format_props.imageFormatProperties.maxExtent.depth < info.extent.depth) + { + continue; + } + if (format_props.imageFormatProperties.maxMipLevels < info.mipLevels || + format_props.imageFormatProperties.maxArrayLayers < info.arrayLayers) + { + continue; + } + if ((format_props.imageFormatProperties.sampleCounts & info.samples) != info.samples) + { + continue; + } + + if (external_props.externalMemoryProperties.externalMemoryFeatures & + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR) + { + if (!exportable_modifers.try_push_back(drm_format.modifier)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + + if (external_props.externalMemoryProperties.externalMemoryFeatures & + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) + { + uint64_t flags = + (prop.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT) ? 0 : WSIALLOC_FORMAT_NON_DISJOINT; + wsialloc_format import_format{ drm_format.fourcc, drm_format.modifier, flags }; + if (!importable_formats.try_push_back(import_format)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + } + + return VK_SUCCESS; +} +}; diff --git a/wsi/swapchain_image_create_extensions/external_memory_extension.hpp b/wsi/swapchain_image_create_extensions/external_memory_extension.hpp new file mode 100644 index 0000000..46d6985 --- /dev/null +++ b/wsi/swapchain_image_create_extensions/external_memory_extension.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file external_memory_extension.hpp + */ + +#pragma once + +#include +#include + +#include +#include +#include "util/drm/drm_utils.hpp" + +#include + +#include "swapchain_image_create_info_extension.hpp" +#include "image_compression_control.hpp" + +namespace wsi +{ +using util::MAX_PLANES; + +/** + * @brief + */ +class swapchain_image_create_external_memory : public swapchain_image_create_info_extension +{ +public: + swapchain_image_create_external_memory(std::optional compression, + swapchain_wsialloc_allocator *wsi_allocator, + const util::vector *surface_formats, + VkPhysicalDevice physical_device, const util::allocator &allocator) + : m_compression(compression) + , m_wsi_allocator(wsi_allocator) + , m_surface_formats(surface_formats) + , m_physical_device(physical_device) + , m_allocator(allocator) + , m_plane_layouts(allocator) + , m_drm_mod_info() + , m_external_info() + , m_allocated_format() + { + } + + VkResult extend_image_create_info(VkImageCreateInfo *image_create_info) override; + + VkResult get_surface_compatible_formats(const VkImageCreateInfo &info, + util::vector &importable_formats, + util::vector &exportable_modifers, + util::vector &drm_format_props); + +private: + std::optional m_compression; + swapchain_wsialloc_allocator *m_wsi_allocator; + const util::vector *m_surface_formats; + VkPhysicalDevice m_physical_device; + const util::allocator &m_allocator; + + util::vector m_plane_layouts; + VkImageDrmFormatModifierExplicitCreateInfoEXT m_drm_mod_info; + VkExternalMemoryImageCreateInfoKHR m_external_info; + wsialloc_allocate_result m_allocated_format; +}; + +} /* namespace wsi */ \ No newline at end of file diff --git a/wsi/wayland/surface.cpp b/wsi/wayland/surface.cpp index 38ff3b3..15d9eb4 100644 --- a/wsi/wayland/surface.cpp +++ b/wsi/wayland/surface.cpp @@ -40,7 +40,7 @@ namespace wayland struct formats_vector { - util::vector *formats{ nullptr }; + util::vector *formats{ nullptr }; bool is_out_of_memory{ false }; }; @@ -63,7 +63,7 @@ zwp_linux_dmabuf_v1_modifier_impl(void *data, struct zwp_linux_dmabuf_v1 *dma_bu UNUSED(dma_buf); auto *drm_supported_formats = reinterpret_cast(data); - drm_format_pair format = {}; + util::drm::drm_format_pair format = {}; format.fourcc = drm_format; format.modifier = (static_cast(modifier_hi) << 32) | modifier_low; @@ -89,7 +89,7 @@ zwp_linux_dmabuf_v1_modifier_impl(void *data, struct zwp_linux_dmabuf_v1 *dma_bu */ static VkResult get_supported_formats_and_modifiers(wl_display *display, wl_event_queue *queue, zwp_linux_dmabuf_v1 *dmabuf_interface, - util::vector &supported_formats) + util::vector &supported_formats) { formats_vector drm_supported_formats; drm_supported_formats.formats = &supported_formats; diff --git a/wsi/wayland/surface.hpp b/wsi/wayland/surface.hpp index f060f00..eacd861 100644 --- a/wsi/wayland/surface.hpp +++ b/wsi/wayland/surface.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024 Arm Limited. + * Copyright (c) 2021-2025 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -38,6 +38,8 @@ #include "wl_object_owner.hpp" #include "util/macros.hpp" +#include + namespace wsi { namespace wayland @@ -116,7 +118,7 @@ public: * * The reference is valid throughout the lifetime of this surface. */ - const util::vector &get_formats() const + const util::vector &get_formats() const { return supported_formats; } @@ -162,7 +164,7 @@ private: /** The native Wayland surface */ wl_surface *wayland_surface; /** A list of DRM formats supported by the Wayland compositor on this surface */ - util::vector supported_formats; + util::vector supported_formats; /** Surface properties specific to the Wayland surface. */ surface_properties properties; diff --git a/wsi/wayland/surface_properties.cpp b/wsi/wayland/surface_properties.cpp index 31ddc68..070d20e 100644 --- a/wsi/wayland/surface_properties.cpp +++ b/wsi/wayland/surface_properties.cpp @@ -118,7 +118,7 @@ VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_ static VkResult surface_format_properties_add_modifier_support(VkPhysicalDevice phys_dev, surface_format_properties &format_props, - const drm_format_pair &drm_format, + const util::drm::drm_format_pair &drm_format, bool add_compression = false) { VkPhysicalDeviceExternalImageFormatInfoKHR external_info = {}; @@ -148,7 +148,7 @@ static VkResult surface_format_properties_add_modifier_support(VkPhysicalDevice } static VkResult surface_format_properties_map_add(VkPhysicalDevice phys_dev, surface_format_properties_map &format_map, - VkFormat format, const drm_format_pair &drm_format) + VkFormat format, const util::drm::drm_format_pair &drm_format) { surface_format_properties format_props{ format }; VkResult res = surface_format_properties_add_modifier_support(phys_dev, format_props, drm_format); @@ -170,7 +170,7 @@ static VkResult surface_format_properties_map_add(VkPhysicalDevice phys_dev, sur } static VkResult surface_format_properties_map_init(VkPhysicalDevice phys_dev, surface_format_properties_map &format_map, - const util::vector &drm_format_list) + const util::vector &drm_format_list) { for (const auto &drm_format : drm_format_list) { @@ -189,9 +189,9 @@ static VkResult surface_format_properties_map_init(VkPhysicalDevice phys_dev, su return VK_SUCCESS; } -static VkResult surface_format_properties_map_add_compression(VkPhysicalDevice phys_dev, - surface_format_properties_map &format_map, - const util::vector &drm_format_list) +static VkResult surface_format_properties_map_add_compression( + VkPhysicalDevice phys_dev, surface_format_properties_map &format_map, + const util::vector &drm_format_list) { for (const auto &drm_format : drm_format_list) { diff --git a/wsi/wayland/swapchain.cpp b/wsi/wayland/swapchain.cpp index 009764d..ab0351d 100644 --- a/wsi/wayland/swapchain.cpp +++ b/wsi/wayland/swapchain.cpp @@ -63,10 +63,9 @@ swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCal , m_surface(wsi_surface.get_wl_surface()) , m_wsi_surface(&wsi_surface) , m_buffer_queue(nullptr) - , m_wsi_allocator() + , m_wsi_allocator(nullptr) , m_image_creation_parameters({}, m_allocator, {}, {}) { - m_image_create_info.format = VK_FORMAT_UNDEFINED; } swapchain::~swapchain() @@ -147,7 +146,17 @@ VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKH return VK_ERROR_INITIALIZATION_FAILED; } - TRY(m_wsi_allocator.init()); + auto wsi_allocator = swapchain_wsialloc_allocator::create(); + if (!wsi_allocator.has_value()) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + + m_wsi_allocator = m_allocator.make_unique(std::move(*wsi_allocator)); + if (m_wsi_allocator == nullptr) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } /* * When VK_PRESENT_MODE_MAILBOX_KHR has been chosen by the application we don't @@ -196,7 +205,7 @@ VkResult swapchain::get_surface_compatible_formats(const VkImageCreateInfo &info for (const auto &prop : drm_format_props) { bool is_supported = false; - drm_format_pair drm_format{ util::drm::vk_to_drm_format(info.format), prop.drmFormatModifier }; + util::drm::drm_format_pair drm_format{ util::drm::vk_to_drm_format(info.format), prop.drmFormatModifier }; for (const auto &format : m_wsi_surface->get_formats()) { @@ -326,7 +335,7 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, wayl allocation_params params = { (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0, image_create_info.extent, importable_formats, enable_fixed_rate, avoid_allocation }; wsialloc_allocate_result alloc_result = { {}, { 0 }, { 0 }, { -1 }, false }; - TRY(m_wsi_allocator.allocate(params, &alloc_result)); + TRY(m_wsi_allocator->allocate(params, &alloc_result)); *allocated_format = alloc_result.format; @@ -360,26 +369,6 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, wayl return VK_SUCCESS; } -static VkResult fill_image_create_info(VkImageCreateInfo &image_create_info, - util::vector &image_plane_layouts, - VkImageDrmFormatModifierExplicitCreateInfoEXT &drm_mod_info, - VkExternalMemoryImageCreateInfoKHR &external_info, - wayland_image_data &image_data, uint64_t modifier) -{ - TRY_LOG_CALL(image_data.external_mem.fill_image_plane_layouts(image_plane_layouts)); - - if (image_data.external_mem.is_disjoint()) - { - image_create_info.flags |= VK_IMAGE_CREATE_DISJOINT_BIT; - } - - image_data.external_mem.fill_drm_mod_info(image_create_info.pNext, drm_mod_info, image_plane_layouts, modifier); - image_data.external_mem.fill_external_info(external_info, &drm_mod_info); - image_create_info.pNext = &external_info; - image_create_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; - return VK_SUCCESS; -} - VkResult swapchain::allocate_image(wayland_image_data *image_data) { util::vector importable_formats(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); @@ -460,13 +449,13 @@ VkResult swapchain::create_swapchain_image(VkImageCreateInfo image_create_info, } image.data = image_data; - if (m_image_create_info.format == VK_FORMAT_UNDEFINED) + if (m_image_creation_parameters.m_allocated_format.fourcc == DRM_FORMAT_INVALID) { util::vector importable_formats( util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); util::vector exportable_modifiers(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); - /* Query supported modifers. */ + /* Query supported modifiers. */ util::vector drm_format_props( util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); @@ -491,11 +480,6 @@ VkResult swapchain::create_swapchain_image(VkImageCreateInfo image_create_info, } } - TRY_LOG_CALL(fill_image_create_info( - image_create_info, m_image_creation_parameters.m_image_layout, m_image_creation_parameters.m_drm_mod_info, - m_image_creation_parameters.m_external_info, *image_data, allocated_format.modifier)); - - m_image_create_info = image_create_info; m_image_creation_parameters.m_allocated_format = allocated_format; } @@ -667,8 +651,15 @@ VkResult swapchain::get_required_image_creator_extensions( const VkSwapchainCreateInfoKHR &swapchain_create_info, util::vector> *extensions) { - UNUSED(swapchain_create_info); - UNUSED(extensions); + auto compression_control = swapchain_image_create_compression_control::create( + m_device_data.is_swapchain_compression_control_enabled(), swapchain_create_info); + + if (!extensions->try_push_back(m_allocator.make_unique( + compression_control, m_wsi_allocator.get(), &m_wsi_surface->get_formats(), m_device_data.physical_device, + m_allocator))) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } return VK_SUCCESS; } diff --git a/wsi/wayland/swapchain.hpp b/wsi/wayland/swapchain.hpp index 0f30fce..1297c72 100644 --- a/wsi/wayland/swapchain.hpp +++ b/wsi/wayland/swapchain.hpp @@ -222,7 +222,7 @@ private: /** * @brief Handle to the WSI allocator. */ - swapchain_wsialloc_allocator m_wsi_allocator; + util::unique_ptr m_wsi_allocator; /** * @brief Image creation parameters used for all swapchain images. diff --git a/wsi/wsi_alloc_utils.cpp b/wsi/wsi_alloc_utils.cpp index 82be278..e4d6eb4 100644 --- a/wsi/wsi_alloc_utils.cpp +++ b/wsi/wsi_alloc_utils.cpp @@ -33,15 +33,16 @@ namespace wsi { -VkResult swapchain_wsialloc_allocator::init() +std::optional swapchain_wsialloc_allocator::create() { + wsialloc_allocator *allocator = nullptr; WSIALLOC_ASSERT_VERSION(); - if (wsialloc_new(&m_allocator) != WSIALLOC_ERROR_NONE) + if (wsialloc_new(&allocator) != WSIALLOC_ERROR_NONE) { WSI_LOG_ERROR("Failed to create wsi allocator."); - return VK_ERROR_INITIALIZATION_FAILED; + return std::nullopt; } - return VK_SUCCESS; + return swapchain_wsialloc_allocator(allocator); } VkResult swapchain_wsialloc_allocator::allocate(const allocation_params &input, wsialloc_allocate_result *alloc_result) diff --git a/wsi/wsi_alloc_utils.hpp b/wsi/wsi_alloc_utils.hpp index 99447c0..6f2388a 100644 --- a/wsi/wsi_alloc_utils.hpp +++ b/wsi/wsi_alloc_utils.hpp @@ -30,6 +30,7 @@ #include #include "util/wsialloc/wsialloc.h" +#include #include "util/custom_allocator.hpp" @@ -50,13 +51,31 @@ struct allocation_params class swapchain_wsialloc_allocator { public: - swapchain_wsialloc_allocator(wsialloc_allocator *allocator) - : m_allocator(allocator) + static std::optional create(); + + swapchain_wsialloc_allocator(swapchain_wsialloc_allocator &other) = delete; + swapchain_wsialloc_allocator &operator=(swapchain_wsialloc_allocator &other) = delete; + + swapchain_wsialloc_allocator(swapchain_wsialloc_allocator &&other) + : m_allocator(other.m_allocator) { + other.m_allocator = nullptr; } - swapchain_wsialloc_allocator() - : m_allocator(nullptr){}; + swapchain_wsialloc_allocator &operator=(swapchain_wsialloc_allocator &&other) + { + if (this == &other) + { + return *this; + } + + if (m_allocator != nullptr) + { + wsialloc_delete(m_allocator); + m_allocator = nullptr; + } + std::swap(m_allocator, other.m_allocator); + } ~swapchain_wsialloc_allocator() { @@ -71,7 +90,6 @@ public: return m_allocator; } - VkResult init(); VkResult allocate(const allocation_params &input, wsialloc_allocate_result *alloc_result); private: @@ -79,6 +97,11 @@ private: * @brief Handle to the WSI allocator. */ wsialloc_allocator *m_allocator; + + swapchain_wsialloc_allocator(wsialloc_allocator *allocator) + : m_allocator(allocator) + { + } }; } /* namespace wsi */ \ No newline at end of file