Add support for present mode compatibility

This commit adds support for querying a surface's compatible
presentation modes via VkSurfacePresentModeEXT and
VkSurfacePresentModeCompatibilityEXT, as part of the
VK_EXT_surface_maintenance1 extension.

A new struct present_mode_compatibility has been created to capture
this new functionality.

Our headless implementation supports compability between FIFO and
FIFO_RELAXED. On Wayland, we do not allow compatibility between FIFO
and MAILBOX presentation.

Change-Id: I53659cb2f2aa0ac41e37975cc34aee3ce8317a73
Signed-off-by: Dennis Tsiang <dennis.tsiang@arm.com>
Signed-off-by: Fufu Fang <fufu.fang@arm.com>
This commit is contained in:
Dennis Tsiang 2024-04-09 13:53:58 +01:00 committed by Fufu Fang
parent 8f2722de92
commit 8e02a7ffe3
7 changed files with 200 additions and 33 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2017, 2019, 2021-2022 Arm Limited.
* Copyright (c) 2016-2017, 2019, 2021-2022, 2024 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
@ -70,12 +70,7 @@ wsi_layer_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDe
shared_present_surface_cap_struct->sharedPresentSupportedUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
/*
* Any of the extensions that extend pSurfaceInfo are not supported by the
* swapchain implementation so it is safe to ignore pNext here, even if
* the extensions are supported by the ICD.
*/
return props->get_surface_capabilities(physicalDevice, &pSurfaceCapabilities->surfaceCapabilities);
return props->get_surface_capabilities(physicalDevice, pSurfaceInfo, pSurfaceCapabilities);
}
return instance.disp.GetPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, pSurfaceInfo, pSurfaceCapabilities);

View file

@ -46,6 +46,27 @@ namespace headless
constexpr int max_core_1_0_formats = VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1;
void surface_properties::populate_present_mode_compatibilities()
{
present_mode_compatibilities = {
present_mode_compatibility{
VK_PRESENT_MODE_FIFO_KHR, 1, { VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR } },
present_mode_compatibility{
VK_PRESENT_MODE_FIFO_RELAXED_KHR, 1, { VK_PRESENT_MODE_FIFO_RELAXED_KHR, VK_PRESENT_MODE_FIFO_KHR } },
present_mode_compatibility{
VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, 1, { VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR } },
present_mode_compatibility{
VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, 1, { VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR } },
};
}
surface_properties::surface_properties()
: supported_modes({ VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR,
VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR })
{
populate_present_mode_compatibilities();
}
surface_properties &surface_properties::get_instance()
{
static surface_properties instance;
@ -56,7 +77,16 @@ VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_
VkSurfaceCapabilitiesKHR *surface_capabilities)
{
get_surface_capabilities_common(physical_device, surface_capabilities);
return VK_SUCCESS;
}
VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_device,
const VkPhysicalDeviceSurfaceInfo2KHR *surface_info,
VkSurfaceCapabilities2KHR *surface_capabilities)
{
TRY(check_surface_present_mode_query_is_supported(surface_info, supported_modes));
get_surface_capabilities_common(physical_device, &surface_capabilities->surfaceCapabilities);
get_surface_present_mode_compatibility_common(surface_info, surface_capabilities, present_mode_compatibilities);
return VK_SUCCESS;
}
@ -110,15 +140,7 @@ VkResult surface_properties::get_surface_present_modes(VkPhysicalDevice physical
{
UNUSED(physical_device);
UNUSED(surface);
static const std::array<VkPresentModeKHR, 4> modes = {
VK_PRESENT_MODE_FIFO_KHR,
VK_PRESENT_MODE_FIFO_RELAXED_KHR,
VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,
};
return get_surface_present_modes_common(present_mode_count, present_modes, modes);
return get_surface_present_modes_common(present_mode_count, present_modes, supported_modes);
}
VWL_VKAPI_CALL(VkResult)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, 2022-2023 Arm Limited.
* Copyright (c) 2017-2019, 2022-2024 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
@ -36,9 +36,15 @@ namespace headless
class surface_properties : public wsi::surface_properties
{
public:
surface_properties();
VkResult get_surface_capabilities(VkPhysicalDevice physical_device,
VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) override;
VkResult get_surface_capabilities(VkPhysicalDevice physical_device,
const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
VkSurfaceCapabilities2KHR *pSurfaceCapabilities) override;
VkResult get_surface_formats(VkPhysicalDevice physical_device, uint32_t *surfaceFormatCount,
VkSurfaceFormatKHR *surfaceFormats,
VkSurfaceFormat2KHR *extended_surface_formats) override;
@ -53,6 +59,15 @@ public:
bool is_surface_extension_enabled(const layer::instance_private_data &instance_data) override;
static surface_properties &get_instance();
private:
/* List of supported presentation modes */
std::array<VkPresentModeKHR, 4> supported_modes;
/* Stores compatible presentation modes */
std::array<present_mode_compatibility, 4> present_mode_compatibilities;
void populate_present_mode_compatibilities() override;
};
} /* namespace headless */

View file

@ -41,6 +41,19 @@
namespace wsi
{
static constexpr uint32_t MAX_PRESENT_MODES = 6;
struct present_mode_compatibility
{
/* Presentation mode */
VkPresentModeKHR present_mode;
/* Number of presentation modes compatible */
uint32_t present_mode_count;
/* Stores the compatible presentation modes */
std::array<VkPresentModeKHR, MAX_PRESENT_MODES> compatible_present_modes;
};
/**
* @brief The base surface property query interface.
*/
@ -53,6 +66,13 @@ public:
virtual VkResult get_surface_capabilities(VkPhysicalDevice physical_device,
VkSurfaceCapabilitiesKHR *surface_capabilities) = 0;
/**
* @brief Implementation of vkGetPhysicalDeviceSurfaceCapabilities2KHR for the specific VkSurface type.
*/
virtual VkResult get_surface_capabilities(VkPhysicalDevice physical_device,
const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
VkSurfaceCapabilities2KHR *surface_capabilities) = 0;
/**
* @brief Implementation of vkGetPhysicalDeviceSurfaceFormatsKHR for the specific VkSurface type.
*/
@ -94,6 +114,12 @@ public:
/* There is no maximum theoretically speaking however we choose 6 for practicality */
static constexpr uint32_t MAX_SWAPCHAIN_IMAGE_COUNT = 6;
private:
/**
* @brief Set which presentation modes are compatible with each other for a particular surface
*/
virtual void populate_present_mode_compatibilities() = 0;
};
class surface_format_properties
@ -204,6 +230,36 @@ VkResult surface_properties_formats_helper(It begin, It end, uint32_t *surface_f
return res;
}
/**
* @brief Common function for handling VkSurfacePresentModeEXT.
*
* If VkSurfacePresentModeEXT is present in the pNext chain of VkPhysicalDeviceSurfaceInfo2KHR, then
* the presentation mode specified in the VkSurfacePresentModeEXT struct is checked to see if it is
* supported by the surface.
*
* @param surface_info Pointer to Vulkan surface info struct.
* @param modes Array of presentation modes supported by the surface.
*
* @return VK_SUCCESS on success, VK_ERROR_OUT_OF_HOST_MEMORY otherwise.
*/
template <std::size_t SIZE>
VkResult check_surface_present_mode_query_is_supported(const VkPhysicalDeviceSurfaceInfo2KHR *surface_info,
const std::array<VkPresentModeKHR, SIZE> &modes)
{
auto surface_present_mode =
util::find_extension<VkSurfacePresentModeEXT>(VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT, surface_info);
if (surface_present_mode != nullptr)
{
VkPresentModeKHR present_mode = surface_present_mode->presentMode;
if (std::find(modes.begin(), modes.end(), present_mode) == modes.end())
{
WSI_LOG_ERROR("Querying surface capability support for a present mode that is not supported by the surface");
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
}
return VK_SUCCESS;
}
/**
* @brief Common function for the get_surface_capabilities.
*
@ -255,4 +311,55 @@ VkResult get_surface_present_modes_common(uint32_t *present_mode_count, VkPresen
return res;
}
/**
* @brief Common function for handling VkSurfacePresentModeCompatibilityEXT if it exists in the pNext chain of VkSurfaceCapabilities2KHR.
*
* If pSurfaceInfo contains a VkSurfacePresentModeEXT struct in its pNext chain, and pSurfaceCapabilities contains a VkSurfacePresentModeCompatibilityEXT struct
* then this function fills the VkSurfacePresentModeCompatibilityEXT struct with the presentation modes that are compatible with the presentation mode specified
* in the VkSurfacePresentModeEXT struct.
*
* @param pSurfaceInfo Pointer to surface info that may or may not contain a VkSurfacePresentModeEXT.
* @param pSurfaceCapabilities Pointer to surface capabilities that may or may not contain a VkSurfacePresentModeCompatibilityEXT struct.
* @param present_mode_compatibilities A table containing a mapping of presentation modes and what other modes they are compatible with.
*
*/
template <std::size_t SIZE>
void get_surface_present_mode_compatibility_common(
const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkSurfaceCapabilities2KHR *pSurfaceCapabilities,
const std::array<present_mode_compatibility, SIZE> &present_mode_compatibilities)
{
auto surface_present_mode =
util::find_extension<VkSurfacePresentModeEXT>(VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT, pSurfaceInfo);
auto surface_present_mode_compatibility = util::find_extension<VkSurfacePresentModeCompatibilityEXT>(
VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT, pSurfaceCapabilities);
if (surface_present_mode == nullptr || surface_present_mode_compatibility == nullptr)
{
return;
}
VkPresentModeKHR present_mode = surface_present_mode->presentMode;
auto it = std::find_if(present_mode_compatibilities.begin(), present_mode_compatibilities.end(),
[present_mode](present_mode_compatibility p) { return p.present_mode == present_mode; });
if (it == present_mode_compatibilities.end())
{
WSI_LOG_ERROR("Querying compatible presentation mode support for a presentation mode that is not supported.");
return;
}
const present_mode_compatibility &surface_supported_compatibility = *it;
if (surface_present_mode_compatibility->pPresentModes == nullptr)
{
surface_present_mode_compatibility->presentModeCount = surface_supported_compatibility.present_mode_count;
return;
}
surface_present_mode_compatibility->presentModeCount = std::min(surface_present_mode_compatibility->presentModeCount,
surface_supported_compatibility.present_mode_count);
std::copy(surface_supported_compatibility.compatible_present_modes.begin(),
surface_supported_compatibility.compatible_present_modes.begin() +
surface_present_mode_compatibility->presentModeCount,
surface_present_mode_compatibility->pPresentModes);
}
} /* namespace wsi */

View file

@ -130,7 +130,7 @@ surface::surface(const init_parameters &params)
, wayland_display(params.display)
, wayland_surface(params.surf)
, supported_formats(params.allocator)
, properties(*this, params.allocator)
, properties(this, params.allocator)
, surface_queue(nullptr)
, last_frame_callback(nullptr)
, present_pending(false)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, 2021-2023 Arm Limited.
* Copyright (c) 2017-2019, 2021-2024 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
@ -47,15 +47,24 @@ namespace wsi
namespace wayland
{
surface_properties::surface_properties(surface &wsi_surface, const util::allocator &allocator)
: specific_surface(&wsi_surface)
, supported_formats(allocator)
void surface_properties::populate_present_mode_compatibilities()
{
present_mode_compatibilities = {
present_mode_compatibility{ VK_PRESENT_MODE_FIFO_KHR, 1, { VK_PRESENT_MODE_FIFO_KHR } },
present_mode_compatibility{ VK_PRESENT_MODE_MAILBOX_KHR, 1, { VK_PRESENT_MODE_MAILBOX_KHR } }
};
}
surface_properties::surface_properties(surface *wsi_surface, const util::allocator &allocator)
: specific_surface(wsi_surface)
, supported_formats(allocator)
, supported_modes({ VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_MAILBOX_KHR })
{
populate_present_mode_compatibilities();
}
surface_properties::surface_properties()
: specific_surface(nullptr)
, supported_formats(util::allocator::get_generic())
: surface_properties(nullptr, util::allocator::get_generic())
{
}
@ -68,6 +77,7 @@ surface_properties &surface_properties::get_instance()
VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_device,
VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
{
/* Image count limits */
get_surface_capabilities_common(physical_device, pSurfaceCapabilities);
pSurfaceCapabilities->minImageCount = 2;
@ -75,6 +85,19 @@ VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_
/* Composite alpha */
pSurfaceCapabilities->supportedCompositeAlpha = static_cast<VkCompositeAlphaFlagBitsKHR>(
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR);
return VK_SUCCESS;
}
VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_device,
const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
VkSurfaceCapabilities2KHR *pSurfaceCapabilities)
{
TRY(check_surface_present_mode_query_is_supported(pSurfaceInfo, supported_modes));
/* Image count limits */
get_surface_capabilities(physical_device, &pSurfaceCapabilities->surfaceCapabilities);
get_surface_present_mode_compatibility_common(pSurfaceInfo, pSurfaceCapabilities, present_mode_compatibilities);
return VK_SUCCESS;
}
@ -213,13 +236,7 @@ VkResult surface_properties::get_surface_formats(VkPhysicalDevice physical_devic
VkResult surface_properties::get_surface_present_modes(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes)
{
static const std::array<VkPresentModeKHR, 2> modes = {
VK_PRESENT_MODE_FIFO_KHR,
VK_PRESENT_MODE_MAILBOX_KHR,
};
return get_surface_present_modes_common(pPresentModeCount, pPresentModes, modes);
return get_surface_present_modes_common(pPresentModeCount, pPresentModes, supported_modes);
}
VkResult surface_properties::get_required_device_extensions(util::extension_list &extension_list)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, 2021-2023 Arm Limited.
* Copyright (c) 2017-2019, 2021-2024 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
@ -48,12 +48,15 @@ class surface;
class surface_properties : public wsi::surface_properties
{
public:
surface_properties(surface &wsi_surface, const util::allocator &alloc);
surface_properties(surface *wsi_surface, const util::allocator &alloc);
static surface_properties &get_instance();
VkResult get_surface_capabilities(VkPhysicalDevice physical_device,
VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) override;
VkResult get_surface_capabilities(VkPhysicalDevice physical_device,
const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
VkSurfaceCapabilities2KHR *pSurfaceCapabilities) override;
VkResult get_surface_formats(VkPhysicalDevice physical_device, uint32_t *surfaceFormatCount,
VkSurfaceFormatKHR *surfaceFormats,
VkSurfaceFormat2KHR *extended_surface_formats) override;
@ -77,6 +80,14 @@ private:
surface *specific_surface;
/** Set of supported Vulkan formats by the @ref specific_surface. */
surface_format_properties_map supported_formats;
/* List of supported presentation modes */
std::array<VkPresentModeKHR, 2> supported_modes;
/* Stores compatible presentation modes */
std::array<present_mode_compatibility, 2> present_mode_compatibilities;
void populate_present_mode_compatibilities() override;
};
} // namespace wayland