mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2025-12-20 04:30:11 +01:00
Support VK_KHR_swapchain_mutable_format extension
- Add support for VK_KHR_swapchain_mutable_format extension to the Layer. - Expose support for the VK_KHR_swapchain_mutable_format extension. - Improve find_extension helper API to be spec-correct, const-correct, and clearer by using the right base type (VkBaseInStructure for input, VkBaseOutStructure for output), and concise docs explaining it returns the first matching struct or nullptr. - Correctly use image_create_info instead of m_image_create_info in create_swapchain_image function for Wayland. Signed-off-by: Maged Elnaggar <maged.elnaggar@arm.com> Change-Id: Id40b28977e63ba76012d3a8f693327f757d75dcd
This commit is contained in:
parent
edcd2c2629
commit
fb23a9b14e
12 changed files with 291 additions and 21 deletions
|
|
@ -327,7 +327,8 @@ add_library(${PROJECT_NAME} SHARED
|
|||
wsi/synchronization.cpp
|
||||
wsi/wsi_factory.cpp
|
||||
wsi/swapchain_image_creator.cpp
|
||||
wsi/swapchain_image_create_extensions/image_compression_control.cpp)
|
||||
wsi/swapchain_image_create_extensions/image_compression_control.cpp
|
||||
wsi/swapchain_image_create_extensions/mutable_format_extension.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)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ implements the following extensions:
|
|||
* VK_EXT_swapchain_maintenance1
|
||||
* VK_EXT_present_mode_fifo_latest_ready (For Headless and Wayland only)
|
||||
* VK_KHR_present_id2
|
||||
* VK_KHR_swapchain_mutable_format (For Headless and Wayland only)
|
||||
|
||||
## Building
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,10 @@
|
|||
{
|
||||
"name": "VK_EXT_present_mode_fifo_latest_ready",
|
||||
"spec_version": "1"
|
||||
},
|
||||
{
|
||||
"name": "VK_KHR_swapchain_mutable_format",
|
||||
"spec_version": "1"
|
||||
}
|
||||
],
|
||||
"disable_environment": {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2022, 2024 Arm Limited.
|
||||
* Copyright (c) 2021-2022, 2024-2025 Arm Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
|
|
@ -77,26 +77,60 @@
|
|||
|
||||
namespace util
|
||||
{
|
||||
/**
|
||||
* @brief Search a Vulkan pNext chain (read-only) for a specific extension struct.
|
||||
*
|
||||
* Use for input pNext chains (application → driver), e.g. VkSwapchainCreateInfoKHR::pNext.
|
||||
* Walks the chain via VkBaseInStructure and returns the first match.
|
||||
*
|
||||
* @tparam T Vulkan struct type to find (e.g., VkImageFormatListCreateInfo)
|
||||
* @param sType VkStructureType corresponding to T
|
||||
* @param pNext Head of the pNext chain (may be nullptr)
|
||||
* @return const T* to the first matching node; nullptr if not found
|
||||
*
|
||||
* @note Unknown sTypes are skipped per Vulkan forward-compat rules.
|
||||
*/
|
||||
template <typename T>
|
||||
const T *find_extension(VkStructureType sType, const void *pNext)
|
||||
inline const T *find_extension(VkStructureType sType, const void *pNext) noexcept
|
||||
{
|
||||
auto entry = reinterpret_cast<const VkBaseOutStructure *>(pNext);
|
||||
while (entry && entry->sType != sType)
|
||||
auto p = reinterpret_cast<const VkBaseInStructure *>(pNext);
|
||||
while (p)
|
||||
{
|
||||
entry = entry->pNext;
|
||||
if (p->sType == sType)
|
||||
{
|
||||
return reinterpret_cast<const T *>(p);
|
||||
}
|
||||
p = p->pNext;
|
||||
}
|
||||
return reinterpret_cast<const T *>(entry);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Search a Vulkan pNext chain (writable) for a specific extension struct.
|
||||
*
|
||||
* Use for output pNext chains (driver → application), e.g. VkPhysicalDeviceFeatures2::pNext.
|
||||
* Walks the chain via VkBaseOutStructure and returns the first match.
|
||||
*
|
||||
* @tparam T Vulkan struct type to find (e.g., VkPhysicalDeviceVulkan11Features)
|
||||
* @param sType VkStructureType corresponding to T
|
||||
* @param pNext Head of the pNext chain (may be nullptr)
|
||||
* @return T* to the first matching node; nullptr if not found
|
||||
*
|
||||
* @note Unknown sTypes are skipped per Vulkan forward-compat rules.
|
||||
*/
|
||||
template <typename T>
|
||||
T *find_extension(VkStructureType sType, void *pNext)
|
||||
inline T *find_extension(VkStructureType sType, void *pNext) noexcept
|
||||
{
|
||||
auto entry = reinterpret_cast<VkBaseOutStructure *>(pNext);
|
||||
while (entry && entry->sType != sType)
|
||||
auto p = reinterpret_cast<VkBaseOutStructure *>(pNext);
|
||||
while (p)
|
||||
{
|
||||
entry = entry->pNext;
|
||||
if (p->sType == sType)
|
||||
{
|
||||
return reinterpret_cast<T *>(p);
|
||||
}
|
||||
p = p->pNext;
|
||||
}
|
||||
return reinterpret_cast<T *>(entry);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
|||
|
|
@ -142,6 +142,12 @@ VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKH
|
|||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
if (is_mutable_format_enabled())
|
||||
{
|
||||
WSI_LOG_ERROR("Mutable format swapchain is not supported for display backend");
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include "util/helpers.hpp"
|
||||
|
||||
#include "swapchain_base.hpp"
|
||||
#include "swapchain_image_create_extensions/mutable_format_extension.hpp"
|
||||
#include "wsi_factory.hpp"
|
||||
|
||||
#include "extensions/present_timing.hpp"
|
||||
|
|
@ -274,6 +275,14 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
|
|||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
const bool want_mutable_format = (swapchain_create_info->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) != 0;
|
||||
|
||||
/* Enable mutable-format early so backends can react in init_platform. */
|
||||
if (want_mutable_format)
|
||||
{
|
||||
enable_mutable_format();
|
||||
}
|
||||
|
||||
/* We have allocated images, we can call the platform init function if something needs to be done. */
|
||||
bool use_presentation_thread = true;
|
||||
TRY_LOG_CALL(init_platform(device, swapchain_create_info, use_presentation_thread));
|
||||
|
|
@ -283,11 +292,11 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
|
|||
TRY_LOG_CALL(init_page_flip_thread());
|
||||
}
|
||||
|
||||
/* Initialize the image creator, and attach any required extensions */
|
||||
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)
|
||||
if (VkResult result = m_free_image_semaphore.init(m_swapchain_images.size()); result != VK_SUCCESS)
|
||||
{
|
||||
assert(result == VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
return result;
|
||||
|
|
@ -566,7 +575,11 @@ VkResult swapchain_base::get_swapchain_images(uint32_t *swapchain_image_count, V
|
|||
|
||||
VkResult swapchain_base::create_aliased_image_handle(VkImage *image)
|
||||
{
|
||||
return m_device_data.disp.CreateImage(m_device, &m_image_create_info, get_allocation_callbacks(), image);
|
||||
/* Build an alias VkImageCreateInfo compatible with swapchain memory binding. */
|
||||
VkImageCreateInfo alias_info = m_image_create_info;
|
||||
alias_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
return m_device_data.disp.CreateImage(m_device, &alias_info, get_allocation_callbacks(), image);
|
||||
}
|
||||
|
||||
VkResult swapchain_base::get_swapchain_status()
|
||||
|
|
@ -832,8 +845,26 @@ VkResult swapchain_base::image_creator_init(const VkSwapchainCreateInfoKHR &swap
|
|||
{
|
||||
m_image_creator.init(swapchain_create_info);
|
||||
|
||||
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> extensions(m_allocator);
|
||||
util::vector<util::unique_ptr<swapchain_image_create_info_extension>> extensions(
|
||||
util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
|
||||
|
||||
TRY_LOG_CALL(get_required_image_creator_extensions(swapchain_create_info, &extensions));
|
||||
|
||||
if (is_mutable_format_enabled())
|
||||
{
|
||||
const auto *image_format_list = util::find_extension<VkImageFormatListCreateInfo>(
|
||||
VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, swapchain_create_info.pNext);
|
||||
auto mutable_format_uptr = swapchain_image_create_mutable_format::create_unique(image_format_list, m_allocator);
|
||||
if (!mutable_format_uptr)
|
||||
{
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
if (!extensions.try_push_back(std::move(mutable_format_uptr)))
|
||||
{
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
TRY_LOG_CALL(m_image_creator.add_extensions(extensions));
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -316,6 +316,24 @@ public:
|
|||
|
||||
bool add_swapchain_extension(util::unique_ptr<wsi_ext> extension);
|
||||
|
||||
/**
|
||||
* @brief Enable mutable format swapchain support.
|
||||
*/
|
||||
void enable_mutable_format()
|
||||
{
|
||||
m_mutable_format_enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if mutable format swapchain support is enabled.
|
||||
*
|
||||
* @return true if mutable format swapchain support is enabled, false otherwise.
|
||||
*/
|
||||
bool is_mutable_format_enabled() const
|
||||
{
|
||||
return m_mutable_format_enabled;
|
||||
}
|
||||
|
||||
protected:
|
||||
layer::device_private_data &m_device_data;
|
||||
|
||||
|
|
@ -677,6 +695,11 @@ private:
|
|||
*/
|
||||
swapchain_image_creator m_image_creator;
|
||||
|
||||
/**
|
||||
* @brief Flag indicating if mutable format swapchain support is enabled.
|
||||
*/
|
||||
bool m_mutable_format_enabled{ false };
|
||||
|
||||
/** @brief Signal semaphores for queue submit.
|
||||
*/
|
||||
std::array<VkSemaphore, SIGNAL_SEMAPHORE_MAX_NUM> signal_semaphores;
|
||||
|
|
|
|||
|
|
@ -232,4 +232,5 @@ VkResult swapchain_image_create_external_memory::get_surface_compatible_formats(
|
|||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace wsi */
|
||||
|
|
|
|||
|
|
@ -85,4 +85,4 @@ VkResult swapchain_image_create_compression_control::extend_image_create_info(Vk
|
|||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
};
|
||||
} /* namespace wsi */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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 mutable_format_extension.cpp
|
||||
*/
|
||||
|
||||
#include "mutable_format_extension.hpp"
|
||||
|
||||
namespace wsi
|
||||
{
|
||||
|
||||
util::unique_ptr<swapchain_image_create_mutable_format> swapchain_image_create_mutable_format::create_unique(
|
||||
const VkImageFormatListCreateInfo *image_format_list, util::allocator allocator)
|
||||
{
|
||||
/** Allocate the object directly using the allocator so we don't need to move. */
|
||||
auto ptr = allocator.make_unique<swapchain_image_create_mutable_format>(allocator);
|
||||
if (!ptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ptr->m_format_list.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO;
|
||||
ptr->m_format_list.pNext = nullptr;
|
||||
ptr->m_format_list.viewFormatCount = 0;
|
||||
ptr->m_format_list.pViewFormats = nullptr;
|
||||
|
||||
if (image_format_list && image_format_list->viewFormatCount > 0)
|
||||
{
|
||||
if (!ptr->m_view_formats.try_resize(image_format_list->viewFormatCount))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
for (uint32_t i = 0; i < image_format_list->viewFormatCount; ++i)
|
||||
{
|
||||
ptr->m_view_formats[i] = image_format_list->pViewFormats[i];
|
||||
}
|
||||
ptr->m_format_list.viewFormatCount = image_format_list->viewFormatCount;
|
||||
ptr->m_format_list.pViewFormats = ptr->m_view_formats.data();
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
VkResult swapchain_image_create_mutable_format::extend_image_create_info(VkImageCreateInfo *image_create_info)
|
||||
{
|
||||
/* If this extension is present, mutable format support is requested. */
|
||||
image_create_info->flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR;
|
||||
m_format_list.pNext = image_create_info->pNext;
|
||||
image_create_info->pNext = &m_format_list;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
} /* namespace wsi */
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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 mutable_format_extension.hpp
|
||||
*
|
||||
* @brief Swapchain image create info extension for VK_KHR_swapchain_mutable_format handling.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <util/custom_allocator.hpp>
|
||||
#include "swapchain_image_create_info_extension.hpp"
|
||||
|
||||
namespace wsi
|
||||
{
|
||||
|
||||
class swapchain_image_create_mutable_format : public swapchain_image_create_info_extension
|
||||
{
|
||||
public:
|
||||
swapchain_image_create_mutable_format() = delete;
|
||||
swapchain_image_create_mutable_format(const swapchain_image_create_mutable_format &) = delete;
|
||||
swapchain_image_create_mutable_format &operator=(const swapchain_image_create_mutable_format &) = delete;
|
||||
/**
|
||||
* @brief Create and return a unique_ptr-managed instance using allocator.
|
||||
*
|
||||
* Allocates the object with the provided allocator and initializes its
|
||||
* internal state from the optional VkImageFormatListCreateInfo.
|
||||
*
|
||||
* @return util::unique_ptr owning the instance, or nullptr on failure.
|
||||
*/
|
||||
static util::unique_ptr<swapchain_image_create_mutable_format> create_unique(
|
||||
const VkImageFormatListCreateInfo *image_format_list, util::allocator allocator);
|
||||
/**
|
||||
* @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
|
||||
* @return VkResult indicating success or failure
|
||||
*/
|
||||
VkResult extend_image_create_info(VkImageCreateInfo *image_create_info) override;
|
||||
|
||||
private:
|
||||
friend class util::allocator;
|
||||
/**
|
||||
* @brief Construct the extension.
|
||||
* @param allocator Allocator used to own copied view formats.
|
||||
*/
|
||||
swapchain_image_create_mutable_format(util::allocator &allocator)
|
||||
: m_view_formats(allocator)
|
||||
{
|
||||
}
|
||||
|
||||
util::vector<VkFormat> m_view_formats;
|
||||
VkImageFormatListCreateInfo m_format_list{};
|
||||
};
|
||||
|
||||
} /* namespace wsi */
|
||||
|
|
@ -285,8 +285,10 @@ VkResult swapchain::get_surface_compatible_formats(const VkImageCreateInfo &info
|
|||
|
||||
VkResult result = VK_SUCCESS;
|
||||
{
|
||||
/* Build pNext chain for the format query. */
|
||||
VkPhysicalDeviceExternalImageFormatInfoKHR external_info = {};
|
||||
external_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR;
|
||||
external_info.pNext = nullptr;
|
||||
external_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
|
||||
|
||||
VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_mod_info = {};
|
||||
|
|
@ -306,8 +308,20 @@ VkResult swapchain::get_surface_compatible_formats(const VkImageCreateInfo &info
|
|||
image_info.usage = info.usage;
|
||||
image_info.flags = info.flags;
|
||||
|
||||
VkImageCompressionControlEXT compression_control = {};
|
||||
/* Attach view format list (if any) from the swapchain image creator
|
||||
* to the image_info chain, as required by the spec.
|
||||
*/
|
||||
const auto *image_format_list = util::find_extension<VkImageFormatListCreateInfo>(
|
||||
VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, m_image_create_info.pNext);
|
||||
VkImageFormatListCreateInfo image_format_list_copy = {};
|
||||
if (image_format_list)
|
||||
{
|
||||
image_format_list_copy = util::shallow_copy_extension(image_format_list);
|
||||
image_format_list_copy.pNext = image_info.pNext;
|
||||
image_info.pNext = &image_format_list_copy;
|
||||
}
|
||||
|
||||
VkImageCompressionControlEXT compression_control = {};
|
||||
if (m_device_data.is_swapchain_compression_control_enabled())
|
||||
{
|
||||
auto *ext = get_swapchain_extension<wsi_ext_image_compression_control>();
|
||||
|
|
@ -544,7 +558,7 @@ VkResult swapchain::create_swapchain_image(VkImageCreateInfo image_create_info,
|
|||
m_image_creation_parameters.m_allocated_format = allocated_format;
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue