Merge 'Introduce swapchain_image_creator' into 'main'

See merge request mesa/vulkan-wsi-layer!154
This commit is contained in:
Rosen Zhelev 2025-05-16 16:22:43 +01:00
commit b2484fe518
25 changed files with 1206 additions and 224 deletions

View file

@ -76,6 +76,7 @@ option(ENABLE_INSTRUMENTATION "Pass frame boundary events by using VK_EXT_frame_
if(BUILD_WSI_WAYLAND OR BUILD_WSI_DISPLAY)
set(BUILD_DRM_UTILS true)
set(BUILD_WSIALLOC_UTILS true)
if(SELECT_EXTERNAL_ALLOCATOR STREQUAL "none")
message(FATAL_ERROR "WSI only supported with an external allocator.")
endif()
@ -126,13 +127,26 @@ if(NOT SELECT_EXTERNAL_ALLOCATOR STREQUAL "none" AND EXTERNAL_WSIALLOC_LIBRARY S
target_include_directories(wsialloc PRIVATE util/)
endif()
if(BUILD_WSIALLOC_UTILS)
add_library(wsi_utils STATIC wsi/wsi_alloc_utils.cpp)
target_include_directories(wsi_utils PRIVATE
${PROJECT_SOURCE_DIR}
${VULKAN_CXX_INCLUDE}
${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(wsi_utils drm_utils)
target_include_directories(wsi_utils PRIVATE util/wsialloc)
target_compile_definitions(wsi_utils PRIVATE ${WSI_DEFINES})
endif()
# Wayland WSI
if(BUILD_WSI_WAYLAND)
add_library(wayland_wsi STATIC
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_id_wayland.cpp)
@ -199,6 +213,7 @@ if(BUILD_WSI_WAYLAND)
target_link_libraries(wayland_wsi wsialloc)
endif()
target_link_libraries(wayland_wsi drm_utils ${WAYLAND_CLIENT_LDFLAGS})
target_link_libraries(wayland_wsi wsi_utils)
list(APPEND LINK_WSI_LIBS wayland_wsi)
if(ENABLE_WAYLAND_FIFO_PRESENTATION_THREAD)
target_compile_definitions(wayland_wsi PRIVATE "-DWAYLAND_FIFO_PRESENTATION_THREAD_ENABLED=1")
@ -239,7 +254,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)
if(VULKAN_WSI_LAYER_EXPERIMENTAL)
target_sources(wsi_display PRIVATE wsi/display/present_wait_display.cpp)
@ -260,6 +276,7 @@ if (BUILD_WSI_DISPLAY)
target_compile_options(wsi_display INTERFACE "-DBUILD_WSI_DISPLAY=1")
target_link_libraries(wsi_display ${LIBDRM_LDFLAGS} drm)
target_link_libraries(wsi_display drm_utils)
target_link_libraries(wsi_display wsi_utils)
if(NOT EXTERNAL_WSIALLOC_LIBRARY STREQUAL "")
target_link_libraries(wsi_display ${EXTERNAL_WSIALLOC_LIBRARY})
else()
@ -292,7 +309,9 @@ add_library(${PROJECT_NAME} SHARED
wsi/surface_properties.cpp
wsi/swapchain_base.cpp
wsi/synchronization.cpp
wsi/wsi_factory.cpp)
wsi/wsi_factory.cpp
wsi/swapchain_image_creator.cpp
wsi/swapchain_image_create_extensions/image_compression_control.cpp)
if (VULKAN_WSI_LAYER_EXPERIMENTAL)
target_sources(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/layer/present_timing_api.cpp)
target_sources(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/wsi/extensions/present_timing.cpp)

View file

@ -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);

View file

@ -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<util::vector<drm_format_pair>> supported_formats,
util::unique_ptr<util::vector<util::drm::drm_format_pair>> supported_formats,
util::unique_ptr<drm_display_mode> 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<drm_format_pair> &supported_formats)
util::vector<util::drm::drm_format_pair> &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<drm_format_pair> &supported_formats)
util::vector<util::drm::drm_format_pair> &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> drm_display::make_display(const util::allocator &allo
}
#endif
auto supported_formats = allocator.make_unique<util::vector<drm_format_pair>>(allocator);
auto supported_formats = allocator.make_unique<util::vector<util::drm::drm_format_pair>>(allocator);
if (supports_fb_modifiers)
{
@ -365,12 +366,12 @@ std::optional<drm_display> &drm_display::get_display()
return display;
}
const util::vector<drm_format_pair> *drm_display::get_supported_formats() const
const util::vector<util::drm::drm_format_pair> *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) {

View file

@ -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<drm_format_pair> *get_supported_formats() const;
const util::vector<util::drm::drm_format_pair> *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<util::vector<drm_format_pair>> supported_formats,
util::unique_ptr<util::vector<util::drm::drm_format_pair>> supported_formats,
util::unique_ptr<drm_display_mode> 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<util::vector<drm_format_pair>> m_supported_formats;
util::unique_ptr<util::vector<util::drm::drm_format_pair>> m_supported_formats;
/**
* @brief Pointer to available display modes for the connected display.

View file

@ -40,6 +40,8 @@
#include "swapchain.hpp"
#include "present_wait_display.hpp"
#include <wsi/swapchain_image_create_extensions/external_memory_extension.hpp>
namespace wsi
{
@ -60,13 +62,6 @@ swapchain::~swapchain()
{
/* Call the base class teardown */
teardown();
/* Free WSI allocator. */
if (m_wsi_allocator != nullptr)
{
wsialloc_delete(m_wsi_allocator);
}
m_wsi_allocator = nullptr;
}
static void page_flip_event(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
@ -126,13 +121,19 @@ VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKH
UNUSED(device);
UNUSED(swapchain_create_info);
UNUSED(use_presentation_thread);
WSIALLOC_ASSERT_VERSION();
if (wsialloc_new(&m_wsi_allocator) != WSIALLOC_ERROR_NONE)
auto wsi_allocator = swapchain_wsialloc_allocator::create();
if (!wsi_allocator.has_value())
{
WSI_LOG_ERROR("Failed to create wsi allocator.");
return VK_ERROR_INITIALIZATION_FAILED;
}
m_wsi_allocator = m_allocator.make_unique<swapchain_wsialloc_allocator>(std::move(*wsi_allocator));
if (m_wsi_allocator == nullptr)
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
return VK_SUCCESS;
}
@ -162,7 +163,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))
{
@ -267,13 +268,7 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, disp
util::vector<wsialloc_format> &importable_formats,
wsialloc_format *allocated_format, bool avoid_allocation)
{
bool is_protected_memory = (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0;
uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
if (avoid_allocation)
{
allocation_flags |= WSIALLOC_ALLOCATE_NO_MEMORY;
}
bool enable_fixed_rate = false;
if (m_device_data.is_swapchain_compression_control_enabled())
{
auto *ext = get_swapchain_extension<wsi_ext_image_compression_control>();
@ -285,36 +280,18 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, disp
{
if (ext->get_bitmask_for_image_compression_flags() & VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT)
{
allocation_flags |= WSIALLOC_ALLOCATE_HIGHEST_FIXED_RATE_COMPRESSION;
enable_fixed_rate = true;
}
}
}
wsialloc_allocate_info alloc_info = { importable_formats.data(), static_cast<unsigned>(importable_formats.size()),
image_create_info.extent.width, image_create_info.extent.height,
allocation_flags };
wsialloc_allocate_result alloc_result = { .format = { .fourcc = 0, .modifier = 0, .flags = 0 },
.average_row_strides = { 0 },
.offsets = { 0 },
.buffer_fds = { 0 },
.is_disjoint = false };
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));
/* Clear buffer_fds and average_row_strides for error purposes */
for (int i = 0; i < WSIALLOC_MAX_PLANES; ++i)
{
alloc_result.buffer_fds[i] = -1;
}
const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, &alloc_result);
if (res != WSIALLOC_ERROR_NONE)
{
WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
if (res == WSIALLOC_ERROR_NOT_SUPPORTED)
{
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
*allocated_format = alloc_result.format;
auto &external_memory = image_data->external_mem;
external_memory.set_strides(alloc_result.average_row_strides);
external_memory.set_buffer_fds(alloc_result.buffer_fds);
@ -345,26 +322,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<VkSubresourceLayout> &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<wsialloc_format> importable_formats(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
@ -383,8 +340,8 @@ VkResult swapchain::create_framebuffer(const VkImageCreateInfo &image_create_inf
VkResult ret_code = VK_SUCCESS;
std::array<uint32_t, util::MAX_PLANES> strides{ 0, 0, 0, 0 };
std::array<uint64_t, util::MAX_PLANES> 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())
@ -474,7 +431,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<wsialloc_format> importable_formats(
util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
@ -506,11 +463,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;
}
@ -683,6 +635,30 @@ void swapchain::destroy_image(swapchain_image &image)
}
}
VkResult swapchain::get_required_image_creator_extensions(
const VkSwapchainCreateInfoKHR &swapchain_create_info,
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> *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<swapchain_image_create_external_memory>(
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;
}
} /* namespace display */
} /* namespace wsi*/

View file

@ -38,6 +38,8 @@
#include <util/wsialloc/wsialloc.h>
#include <wsi/external_memory.hpp>
#include <wsi/wsi_alloc_utils.hpp>
namespace wsi
{
@ -110,6 +112,17 @@ public:
void destroy_image(swapchain_image &image) override;
protected:
/**
* @brief Get backend specific image create info extensions.
*
* @param swapchain_create_info Swapchain create info.
* @param[out] extensions Backend specific swapchain image create info extensions.
*/
VkResult get_required_image_creator_extensions(
const VkSwapchainCreateInfoKHR &swapchain_create_info,
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> *extensions) override;
private:
VkResult allocate_image(display_image_data *image_data);
@ -133,7 +146,8 @@ private:
*/
VkResult add_required_extensions(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info) override;
wsialloc_allocator *m_wsi_allocator;
util::unique_ptr<swapchain_wsialloc_allocator> m_wsi_allocator;
drm_display_mode *m_display_mode;
image_creation_parameters m_image_creation_parameters;
};

View file

@ -38,12 +38,13 @@
#include <wsi/extensions/present_id.hpp>
#include <wsi/extensions/swapchain_maintenance.hpp>
#include <wsi/extensions/image_compression_control.hpp>
#include "util/macros.hpp"
#include "present_timing_handler.hpp"
#include "present_wait_headless.hpp"
#include <wsi/swapchain_image_create_extensions/image_compression_control.hpp>
namespace wsi
{
namespace headless
@ -69,14 +70,8 @@ swapchain::~swapchain()
VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info)
{
auto compression_control = wsi_ext_image_compression_control::create(device, swapchain_create_info);
if (compression_control)
{
if (!add_swapchain_extension(m_allocator.make_unique<wsi_ext_image_compression_control>(*compression_control)))
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
}
UNUSED(device);
UNUSED(swapchain_create_info);
if (m_device_data.is_present_id_enabled())
{
@ -210,24 +205,7 @@ VkResult swapchain::allocate_and_bind_swapchain_image(VkImageCreateInfo image_cr
VkResult swapchain::create_swapchain_image(VkImageCreateInfo image_create_info, swapchain_image &image)
{
m_image_create_info = image_create_info;
VkImageCompressionControlEXT image_compression_control = {};
if (m_device_data.is_swapchain_compression_control_enabled())
{
auto *ext = get_swapchain_extension<wsi_ext_image_compression_control>();
/* For image compression control, additional requirements to be satisfied such as
* existence of VkImageCompressionControlEXT in swaphain_create_info for
* the ext to be added to the list. So we check whether we got a valid pointer
* and proceed if yes. */
if (ext)
{
image_compression_control = ext->get_compression_control_properties();
image_compression_control.pNext = m_image_create_info.pNext;
m_image_create_info.pNext = &image_compression_control;
}
}
return m_device_data.disp.CreateImage(m_device, &m_image_create_info, get_allocation_callbacks(), &image.image);
return m_device_data.disp.CreateImage(m_device, &image_create_info, get_allocation_callbacks(), &image.image);
}
void swapchain::present_image(const pending_present_request &pending_present)
@ -294,5 +272,25 @@ VkResult swapchain::bind_swapchain_image(VkDevice &device, const VkBindImageMemo
return device_data.disp.BindImageMemory(device, bind_image_mem_info->image, memory, 0);
}
VkResult swapchain::get_required_image_creator_extensions(
const VkSwapchainCreateInfoKHR &swapchain_create_info,
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> *extensions)
{
assert(extensions != nullptr);
auto compression_control = swapchain_image_create_compression_control::create(
m_device_data.is_swapchain_compression_control_enabled(), swapchain_create_info);
if (compression_control)
{
if (!extensions->try_push_back(
m_allocator.make_unique<swapchain_image_create_compression_control>(*compression_control)))
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
}
return VK_SUCCESS;
}
} /* namespace headless */
} /* namespace wsi */

View file

@ -125,6 +125,16 @@ protected:
VkResult bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info,
const VkBindImageMemorySwapchainInfoKHR *bind_sc_info) override;
/**
* @brief Get backend specific image create info extensions.
*
* @param swapchain_create_info Swapchain create info.
* @param[out] extensions Backend specific swapchain image create info extensions.
*/
VkResult get_required_image_creator_extensions(
const VkSwapchainCreateInfoKHR &swapchain_create_info,
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> *extensions) override;
private:
/**
* @brief Adds required extensions to the extension list of the swapchain

View file

@ -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.
*

View file

@ -225,6 +225,7 @@ swapchain_base::swapchain_base(layer::device_private_data &dev_data, const VkAll
, m_error_state(VK_NOT_READY)
, m_started_presenting(false)
, m_extensions(m_allocator)
, m_image_creator(m_allocator)
{
}
@ -269,23 +270,8 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
TRY_LOG_CALL(init_page_flip_thread());
}
VkImageCreateInfo image_create_info = {};
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_create_info.pNext = nullptr;
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = swapchain_create_info->imageFormat;
image_create_info.extent = { swapchain_create_info->imageExtent.width, swapchain_create_info->imageExtent.height,
1 };
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = swapchain_create_info->imageArrayLayers;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = swapchain_create_info->imageUsage;
image_create_info.flags = 0;
image_create_info.sharingMode = swapchain_create_info->imageSharingMode;
image_create_info.queueFamilyIndexCount = swapchain_create_info->queueFamilyIndexCount;
image_create_info.pQueueFamilyIndices = swapchain_create_info->pQueueFamilyIndices;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
TRY_LOG_CALL(image_creator_init(*swapchain_create_info));
m_image_create_info = m_image_creator.get_image_create_info();
VkResult result = m_free_image_semaphore.init(m_swapchain_images.size());
if (result != VK_SUCCESS)
@ -298,7 +284,7 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
swapchain_create_info->flags & VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT;
for (auto &img : m_swapchain_images)
{
TRY(create_swapchain_image(image_create_info, img));
TRY(create_swapchain_image(m_image_create_info, img));
if (image_deferred_allocation)
{
@ -306,7 +292,7 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
}
else
{
TRY_LOG_CALL(allocate_and_bind_swapchain_image(image_create_info, img));
TRY_LOG_CALL(allocate_and_bind_swapchain_image(m_image_create_info, img));
}
VkSemaphoreCreateInfo semaphore_info = {};
@ -778,4 +764,15 @@ bool swapchain_base::add_swapchain_extension(util::unique_ptr<wsi_ext> extension
return m_extensions.add_extension(std::move(extension));
}
VkResult swapchain_base::image_creator_init(const VkSwapchainCreateInfoKHR &swapchain_create_info)
{
m_image_creator.init(swapchain_create_info);
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> extensions(m_allocator);
TRY_LOG_CALL(get_required_image_creator_extensions(swapchain_create_info, &extensions));
TRY_LOG_CALL(m_image_creator.add_extensions(extensions));
return VK_SUCCESS;
}
} /* namespace wsi */

View file

@ -48,6 +48,7 @@
#include "extensions/frame_boundary.hpp"
#include "extensions/wsi_extension.hpp"
#include "swapchain_image_creator.hpp"
#include "util/macros.hpp"
namespace wsi
@ -479,12 +480,22 @@ protected:
return VK_SUCCESS;
}
/**
* @brief Get backend specific image create info extensions.
*
* @param swapchain_create_info Swapchain create info.
* @param[in,out] extensions Swapchain image create info extensions filled by the backend.
*/
virtual VkResult get_required_image_creator_extensions(
const VkSwapchainCreateInfoKHR &swapchain_create_info,
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> *extensions) = 0;
/**
* @brief Base swapchain teardown.
*
* Even though the inheritance gives us a nice way to defer display specific allocation
* and presentation outside of the base class, it however robs the children classes - which
* also happen to do some of their state setting - the oppurtunity to do the last clean up
* also happen to do some of their state setting - the opportunity to do the last clean up
* call, as the base class' destructor is called at the end. This method provides a way to do it.
* The destructor is a virtual function and much of the swapchain teardown happens in this method
* which gets called from the child's destructor.
@ -709,6 +720,18 @@ private:
* @brief Holds the swapchain extensions and related functionalities.
*/
wsi_ext_maintainer m_extensions;
/**
* @brief Holds the VkImageCreateInfo and backend specific image create info extensions.
*/
swapchain_image_creator m_image_creator;
/**
* @brief Initialize m_image_creator.
*
* @param swapchain_create_info Swapchain create info.
*/
VkResult image_creator_init(const VkSwapchainCreateInfoKHR &swapchain_create_info);
};
} /* namespace wsi */

View file

@ -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 <cassert>
#include <util/helpers.hpp>
#include <util/format_modifiers.hpp>
#include <layer/private_data.hpp>
#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<wsialloc_format> importable_formats(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
util::vector<uint64_t> exportable_modifiers(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
/* Query supported modifers. */
util::vector<VkDrmFormatModifierPropertiesEXT> 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<uint32_t>(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<wsialloc_format> &importable_formats,
util::vector<uint64_t> &exportable_modifers, util::vector<VkDrmFormatModifierPropertiesEXT> &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;
}
};

View file

@ -0,0 +1,107 @@
/*
* 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 <optional>
#include <utility>
#include <util/custom_allocator.hpp>
#include <util/macros.hpp>
#include "util/drm/drm_utils.hpp"
#include <wsi/wsi_alloc_utils.hpp>
#include "swapchain_image_create_info_extension.hpp"
#include "image_compression_control.hpp"
namespace wsi
{
/**
* @brief
*/
class swapchain_image_create_external_memory : public swapchain_image_create_info_extension
{
public:
/**
* @brief Constructs a swapchain_image_create_external_memory object.
*
* @param[in] compression Optional compression control parameters for the swapchain image.
* @param[in] wsi_allocator wsialloc allocator pointer.
* @param[in] surface_formats Supported surface formats from the presentation engine.
* @param[in] physical_device Vulkan physical device handle.
* @param[in] allocator User provided allocation callbacks.
*/
swapchain_image_create_external_memory(std::optional<swapchain_image_create_compression_control> compression,
swapchain_wsialloc_allocator *wsi_allocator,
const util::vector<util::drm::drm_format_pair> *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;
/**
* @brief Finds what formats are compatible with the requested swapchain image Vulkan Device and backend surface.
*
* @param info The Swapchain image creation info.
* @param[out] importable_formats A list of formats that can be imported to the Vulkan Device.
* @param[out] exportable_formats A list of formats that can be exported from the Vulkan Device.
* @param[out] drm_format_props A list of all device supported VkDrmFormatModifierPropertiesEXT.
*
* @return VK_SUCCESS or VK_ERROR_OUT_OF_HOST_MEMORY
*/
VkResult get_surface_compatible_formats(const VkImageCreateInfo &info,
util::vector<wsialloc_format> &importable_formats,
util::vector<uint64_t> &exportable_modifers,
util::vector<VkDrmFormatModifierPropertiesEXT> &drm_format_props);
private:
std::optional<swapchain_image_create_compression_control> m_compression;
swapchain_wsialloc_allocator *m_wsi_allocator;
const util::vector<util::drm::drm_format_pair> *m_surface_formats;
VkPhysicalDevice m_physical_device;
const util::allocator &m_allocator;
util::vector<VkSubresourceLayout> m_plane_layouts;
VkImageDrmFormatModifierExplicitCreateInfoEXT m_drm_mod_info;
VkExternalMemoryImageCreateInfoKHR m_external_info;
wsialloc_allocate_result m_allocated_format;
};
} /* namespace wsi */

View file

@ -0,0 +1,88 @@
/*
* 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 image_compression_control.cpp
*
* @brief Contains the implementation for VK_EXT_image_compression_control extension.
*/
#include <cassert>
#include <util/helpers.hpp>
#include "image_compression_control.hpp"
namespace wsi
{
swapchain_image_create_compression_control::swapchain_image_create_compression_control(
const VkImageCompressionControlEXT &extension)
: m_compression_control{ VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT, nullptr, extension.flags,
extension.compressionControlPlaneCount, m_array_fixed_rate_flags }
{
for (uint32_t i = 0; i < extension.compressionControlPlaneCount; i++)
{
m_compression_control.pFixedRateFlags[i] = extension.pFixedRateFlags[i];
}
}
swapchain_image_create_compression_control::swapchain_image_create_compression_control(
const swapchain_image_create_compression_control &extension)
: swapchain_image_create_compression_control(extension.m_compression_control)
{
}
VkImageCompressionControlEXT swapchain_image_create_compression_control::get_compression_control_properties()
{
return m_compression_control;
}
VkImageCompressionFlagsEXT swapchain_image_create_compression_control::get_bitmask_for_image_compression_flags()
{
return m_compression_control.flags;
}
std::optional<swapchain_image_create_compression_control> swapchain_image_create_compression_control::create(
bool compression_enabled, const VkSwapchainCreateInfoKHR &swapchain_create_info)
{
const auto *image_compression_control = util::find_extension<VkImageCompressionControlEXT>(
VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT, swapchain_create_info.pNext);
if (compression_enabled && image_compression_control != nullptr)
{
return swapchain_image_create_compression_control{ *image_compression_control };
}
return std::nullopt;
}
VkResult swapchain_image_create_compression_control::extend_image_create_info(VkImageCreateInfo *image_create_info)
{
assert(image_create_info != nullptr);
m_compression_control.pNext = image_create_info->pNext;
image_create_info->pNext = &m_compression_control;
return VK_SUCCESS;
}
};

View file

@ -0,0 +1,121 @@
/*
* 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 image_compression_control.hpp
*
* @brief Contains the implementation for VK_EXT_image_compression_control extension.
*
*/
#pragma once
#include <optional>
#include <utility>
#include <util/custom_allocator.hpp>
#include <util/macros.hpp>
#include "swapchain_image_create_info_extension.hpp"
namespace wsi
{
using util::MAX_PLANES;
/**
* @brief Image compresssion control extension class
*
* This class implements the image compression control features.
* Backends needing additional features will create its own local
* copy and inherit this class.
*/
class swapchain_image_create_compression_control : public swapchain_image_create_info_extension
{
public:
swapchain_image_create_compression_control(const swapchain_image_create_compression_control &extension);
swapchain_image_create_compression_control &operator=(const swapchain_image_create_compression_control &extension)
{
if (this == &extension)
{
return *this;
}
auto compression_control = swapchain_image_create_compression_control(extension);
std::swap(m_compression_control, compression_control.m_compression_control);
for (uint32_t i = 0; i < compression_control.m_compression_control.compressionControlPlaneCount; i++)
{
m_compression_control.pFixedRateFlags[i] = compression_control.m_compression_control.pFixedRateFlags[i];
}
return *this;
}
/**
* @brief Create swapchain_image_create_compression_control class if deemed necessary.
*
* @param device The Vulkan device
* @param swapchain_create_info Swapchain create info
* @return Valid swapchain_image_create_compression_control if requested by application,
* otherwise - an empty optional.
*/
static std::optional<swapchain_image_create_compression_control> create(
bool compression_enabled, const VkSwapchainCreateInfoKHR &swapchain_create_info);
/**
* @brief This API is used to get the compression control properties of an image.
*
* @return The image compression control properties.
*/
VkImageCompressionControlEXT get_compression_control_properties();
/**
* @brief This API is used to get the bitmask for image compression flags.
*
* @return The bitmask for image compression flags.
*/
VkImageCompressionFlagsEXT get_bitmask_for_image_compression_flags();
VkResult extend_image_create_info(VkImageCreateInfo *image_create_info) override;
private:
/**
* @brief Constructor for the swapchain_image_create_compression_control class.
*
* @param extension Reference to VkImageCompressionControlEXT structure.
*/
swapchain_image_create_compression_control(const VkImageCompressionControlEXT &extension);
/**
* @brief Array to hold the pFixedRateFlags.
*/
VkImageCompressionFixedRateFlagsEXT m_array_fixed_rate_flags[MAX_PLANES];
/**
* @brief Image compression control properties.
*/
VkImageCompressionControlEXT m_compression_control;
};
} /* namespace wsi */

View file

@ -0,0 +1,54 @@
/*
* 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 swapchain_image_create_info_extension.hpp
*
* @brief Base class for swapchain image create info extensions.
*/
#pragma once
#include <vulkan/vulkan.h>
namespace wsi
{
class swapchain_image_create_info_extension
{
public:
/**
* @brief Extend image_create_info pNext with extension specific data.
*
* A swapchain image create info extension will use this function to add its
* extension specific data to pNext of image_create_info.
*
* @param[in, out] image_create_info VkImageCreateInfo for creating swapchain images
*/
virtual VkResult extend_image_create_info(VkImageCreateInfo *image_create_info) = 0;
virtual ~swapchain_image_create_info_extension() = default;
};
} /* namespace wsi */

View file

@ -0,0 +1,72 @@
/*
* 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 swapchain_image_creator.cpp
*/
#include "swapchain_image_creator.hpp"
#include "swapchain_image_create_extensions/swapchain_image_create_info_extension.hpp"
#include "util/helpers.hpp"
namespace wsi
{
void swapchain_image_creator::init(const VkSwapchainCreateInfoKHR &swapchain_create_info)
{
m_image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
m_image_create_info.pNext = nullptr;
m_image_create_info.imageType = VK_IMAGE_TYPE_2D;
m_image_create_info.format = swapchain_create_info.imageFormat;
m_image_create_info.extent = { swapchain_create_info.imageExtent.width, swapchain_create_info.imageExtent.height,
1 };
m_image_create_info.mipLevels = 1;
m_image_create_info.arrayLayers = swapchain_create_info.imageArrayLayers;
m_image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
m_image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
m_image_create_info.usage = swapchain_create_info.imageUsage;
m_image_create_info.flags = 0;
m_image_create_info.sharingMode = swapchain_create_info.imageSharingMode;
m_image_create_info.queueFamilyIndexCount = swapchain_create_info.queueFamilyIndexCount;
m_image_create_info.pQueueFamilyIndices = swapchain_create_info.pQueueFamilyIndices;
m_image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
VkResult swapchain_image_creator::add_extensions(
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> &extensions)
{
for (auto &extension : extensions)
{
TRY(extension->extend_image_create_info(&m_image_create_info));
if (!m_extensions.try_push_back(std::move(extension)))
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
}
return VK_SUCCESS;
}
} /* namespace wsi */

View file

@ -0,0 +1,87 @@
/*
* 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 swapchain_image_creator.hpp
*/
#pragma once
#include <vulkan/vulkan.h>
#include <util/custom_allocator.hpp>
#include <wsi/swapchain_image_create_extensions/swapchain_image_create_info_extension.hpp>
namespace wsi
{
/**
* @brief This class is responsible for owning and extending a swapchain's image
* creation info.
*/
class swapchain_image_creator
{
public:
swapchain_image_creator(const util::allocator &allocator)
: m_image_create_info()
, m_extensions(allocator)
{
m_image_create_info.format = VK_FORMAT_UNDEFINED;
};
/**
* @brief Create image create info.
*
* @param swapchain_create_info Swapchain create info.
*/
void init(const VkSwapchainCreateInfoKHR &swapchain_create_info);
/**
* @brief Extend create info with extension data.
*
* @param extensions Swapchain image create info extensions.
*
* @return VK_SUCCESS on success, an appropriate error code on failure.
*
* @note The extensions will be moved out of the vector and will become nullptr.
*/
VkResult add_extensions(util::vector<util::unique_ptr<swapchain_image_create_info_extension>> &extensions);
VkImageCreateInfo get_image_create_info() const
{
return m_image_create_info;
}
private:
/**
* @brief Image create info used for all swapchain images.
*/
VkImageCreateInfo m_image_create_info;
/**
* @brief Swapchain image extensions needed for extending image create info.
*/
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> m_extensions;
};
} /* namespace wsi */

View file

@ -40,7 +40,7 @@ namespace wayland
struct formats_vector
{
util::vector<drm_format_pair> *formats{ nullptr };
util::vector<util::drm::drm_format_pair> *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<formats_vector *>(data);
drm_format_pair format = {};
util::drm::drm_format_pair format = {};
format.fourcc = drm_format;
format.modifier = (static_cast<uint64_t>(modifier_hi) << 32) | modifier_low;
@ -101,7 +101,7 @@ wp_presentation_clock_id_impl(void *data, struct wp_presentation *wp_presentatio
*/
static VkResult get_supported_formats_and_modifiers(wl_display *display, wl_event_queue *queue,
zwp_linux_dmabuf_v1 *dmabuf_interface,
util::vector<drm_format_pair> &supported_formats)
util::vector<util::drm::drm_format_pair> &supported_formats)
{
formats_vector drm_supported_formats;
drm_supported_formats.formats = &supported_formats;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2024-2025 Arm Limited.
* Copyright (c) 2021-2025 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
@ -39,6 +39,8 @@
#include "wl_object_owner.hpp"
#include "util/macros.hpp"
#include <util/drm/drm_utils.hpp>
namespace wsi
{
namespace wayland
@ -128,7 +130,7 @@ public:
*
* The reference is valid throughout the lifetime of this surface.
*/
const util::vector<drm_format_pair> &get_formats() const
const util::vector<util::drm::drm_format_pair> &get_formats() const
{
return supported_formats;
}
@ -182,7 +184,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<drm_format_pair> supported_formats;
util::vector<util::drm::drm_format_pair> supported_formats;
/** Surface properties specific to the Wayland surface. */
surface_properties properties;

View file

@ -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_pair> &drm_format_list)
const util::vector<util::drm::drm_format_pair> &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_pair> &drm_format_list)
static VkResult surface_format_properties_map_add_compression(
VkPhysicalDevice phys_dev, surface_format_properties_map &format_map,
const util::vector<util::drm::drm_format_pair> &drm_format_list)
{
for (const auto &drm_format : drm_format_list)
{

View file

@ -47,6 +47,8 @@
#include <wsi/extensions/swapchain_maintenance.hpp>
#include <wsi/extensions/present_id.hpp>
#include <wsi/swapchain_image_create_extensions/external_memory_extension.hpp>
#include "present_timing_handler.hpp"
#include "present_id_wayland.hpp"
#include "present_wait_wayland.hpp"
@ -67,18 +69,12 @@ swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCal
, m_wsi_allocator(nullptr)
, m_image_creation_parameters({}, m_allocator, {}, {})
{
m_image_create_info.format = VK_FORMAT_UNDEFINED;
}
swapchain::~swapchain()
{
teardown();
if (m_wsi_allocator != nullptr)
{
wsialloc_delete(m_wsi_allocator);
}
m_wsi_allocator = nullptr;
if (m_buffer_queue != nullptr)
{
wl_event_queue_destroy(m_buffer_queue);
@ -179,13 +175,18 @@ VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKH
return VK_ERROR_INITIALIZATION_FAILED;
}
WSIALLOC_ASSERT_VERSION();
if (wsialloc_new(&m_wsi_allocator) != WSIALLOC_ERROR_NONE)
auto wsi_allocator = swapchain_wsialloc_allocator::create();
if (!wsi_allocator.has_value())
{
WSI_LOG_ERROR("Failed to create wsi allocator.");
return VK_ERROR_INITIALIZATION_FAILED;
}
m_wsi_allocator = m_allocator.make_unique<swapchain_wsialloc_allocator>(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
* initialize the page flip thread so the present_image function can be called
@ -241,7 +242,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())
{
@ -351,13 +352,7 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, wayl
util::vector<wsialloc_format> &importable_formats,
wsialloc_format *allocated_format, bool avoid_allocation)
{
bool is_protected_memory = (image_create_info.flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0;
uint64_t allocation_flags = is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
if (avoid_allocation)
{
allocation_flags |= WSIALLOC_ALLOCATE_NO_MEMORY;
}
bool enable_fixed_rate = false;
if (m_device_data.is_swapchain_compression_control_enabled())
{
auto *ext = get_swapchain_extension<wsi_ext_image_compression_control>();
@ -369,33 +364,18 @@ VkResult swapchain::allocate_wsialloc(VkImageCreateInfo &image_create_info, wayl
{
if (ext->get_bitmask_for_image_compression_flags() & VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT)
{
allocation_flags |= WSIALLOC_ALLOCATE_HIGHEST_FIXED_RATE_COMPRESSION;
enable_fixed_rate = true;
}
}
}
wsialloc_allocate_info alloc_info = { importable_formats.data(), static_cast<unsigned>(importable_formats.size()),
image_create_info.extent.width, image_create_info.extent.height,
allocation_flags };
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 };
/* Clear buffer_fds and average_row_strides for error purposes */
for (int i = 0; i < WSIALLOC_MAX_PLANES; ++i)
{
alloc_result.buffer_fds[i] = -1;
alloc_result.average_row_strides[i] = -1;
}
const auto res = wsialloc_alloc(m_wsi_allocator, &alloc_info, &alloc_result);
if (res != WSIALLOC_ERROR_NONE)
{
WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
if (res == WSIALLOC_ERROR_NOT_SUPPORTED)
{
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
TRY(m_wsi_allocator->allocate(params, &alloc_result));
*allocated_format = alloc_result.format;
auto &external_memory = image_data->external_mem;
external_memory.set_strides(alloc_result.average_row_strides);
external_memory.set_buffer_fds(alloc_result.buffer_fds);
@ -426,26 +406,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<VkSubresourceLayout> &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<wsialloc_format> importable_formats(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
@ -526,13 +486,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<wsialloc_format> importable_formats(
util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
util::vector<uint64_t> exportable_modifiers(util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
/* Query supported modifers. */
/* Query supported modifiers. */
util::vector<VkDrmFormatModifierPropertiesEXT> drm_format_props(
util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
@ -557,11 +517,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;
}
@ -758,5 +713,22 @@ VkResult swapchain::bind_swapchain_image(VkDevice &device, const VkBindImageMemo
return image_data->external_mem.bind_swapchain_image_memory(bind_image_mem_info->image);
}
VkResult swapchain::get_required_image_creator_extensions(
const VkSwapchainCreateInfoKHR &swapchain_create_info,
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> *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<swapchain_image_create_external_memory>(
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;
}
} // namespace wayland
} // namespace wsi

View file

@ -41,6 +41,8 @@ extern "C" {
#include "util/custom_allocator.hpp"
#include "wl_object_owner.hpp"
#include <wsi/wsi_alloc_utils.hpp>
#include <wsi/external_memory.hpp>
namespace wsi
@ -181,6 +183,16 @@ protected:
VkResult bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info,
const VkBindImageMemorySwapchainInfoKHR *bind_sc_info) override;
/**
* @brief Get backend specific image create info extensions.
*
* @param swapchain_create_info Swapchain create info.
* @param[out] extensions Backend specific swapchain image create info extensions.
*/
VkResult get_required_image_creator_extensions(
const VkSwapchainCreateInfoKHR &swapchain_create_info,
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> *extensions) override;
private:
VkResult create_wl_buffer(const VkImageCreateInfo &image_create_info, swapchain_image &image,
wayland_image_data *image_data);
@ -210,7 +222,7 @@ private:
/**
* @brief Handle to the WSI allocator.
*/
wsialloc_allocator *m_wsi_allocator;
util::unique_ptr<swapchain_wsialloc_allocator> m_wsi_allocator;
/**
* @brief Image creation parameters used for all swapchain images.

87
wsi/wsi_alloc_utils.cpp Normal file
View file

@ -0,0 +1,87 @@
/*
* 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 wsi_alloc_utils.hpp
*/
#include "wsi_alloc_utils.hpp"
#include "util/log.hpp"
#include <vulkan/vulkan.h>
namespace wsi
{
std::optional<swapchain_wsialloc_allocator> swapchain_wsialloc_allocator::create()
{
wsialloc_allocator *allocator = nullptr;
WSIALLOC_ASSERT_VERSION();
if (wsialloc_new(&allocator) != WSIALLOC_ERROR_NONE)
{
WSI_LOG_ERROR("Failed to create wsi allocator.");
return std::nullopt;
}
return swapchain_wsialloc_allocator(allocator);
}
VkResult swapchain_wsialloc_allocator::allocate(const allocation_params &input, wsialloc_allocate_result *alloc_result)
{
assert(alloc_result != nullptr);
uint64_t allocation_flags = input.is_protected_memory ? WSIALLOC_ALLOCATE_PROTECTED : 0;
if (input.avoid_allocation)
{
allocation_flags |= WSIALLOC_ALLOCATE_NO_MEMORY;
}
if (input.enable_fixed_rate)
{
allocation_flags |= WSIALLOC_ALLOCATE_HIGHEST_FIXED_RATE_COMPRESSION;
}
wsialloc_allocate_info alloc_info = { input.importable_formats.data(),
static_cast<unsigned>(input.importable_formats.size()), input.extent.width,
input.extent.height, allocation_flags };
/* Clear buffer_fds and average_row_strides for error purposes */
for (int i = 0; i < WSIALLOC_MAX_PLANES; ++i)
{
alloc_result->buffer_fds[i] = -1;
alloc_result->average_row_strides[i] = -1;
}
const auto res = wsialloc_alloc(m_allocator, &alloc_info, alloc_result);
if (res != WSIALLOC_ERROR_NONE)
{
WSI_LOG_ERROR("Failed allocation of DMA Buffer. WSI error: %d", static_cast<int>(res));
if (res == WSIALLOC_ERROR_NOT_SUPPORTED)
{
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
return VK_SUCCESS;
}
} /* namespace wsi */

107
wsi/wsi_alloc_utils.hpp Normal file
View file

@ -0,0 +1,107 @@
/*
* 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 wsi_alloc_utils.hpp
*/
#pragma once
#include <optional>
#include "util/wsialloc/wsialloc.h"
#include <util/helpers.hpp>
#include "util/custom_allocator.hpp"
#include <vulkan/vulkan.h>
namespace wsi
{
struct allocation_params
{
bool is_protected_memory;
VkExtent3D extent;
util::vector<wsialloc_format> &importable_formats;
bool enable_fixed_rate;
bool avoid_allocation;
};
class swapchain_wsialloc_allocator
{
public:
static std::optional<swapchain_wsialloc_allocator> 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 &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()
{
if (m_allocator != nullptr)
{
wsialloc_delete(m_allocator);
}
}
wsialloc_allocator *get()
{
return m_allocator;
}
VkResult allocate(const allocation_params &input, wsialloc_allocate_result *alloc_result);
private:
/**
* @brief Handle to the WSI allocator.
*/
wsialloc_allocator *m_allocator;
swapchain_wsialloc_allocator(wsialloc_allocator *allocator)
: m_allocator(allocator)
{
}
};
} /* namespace wsi */