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