mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2025-12-25 15:10:16 +01:00
Support switching presentation modes
Add support for handling VkSwapchainPresentModeInfoEXT and VkSwapchainPresentModesCreateInfoEXT when supplied as part of the pNext chain of VkPresentInfoKHR and VkSwapchainCreateInfoKHR respectively. Since the headless backend has no effect when switching between FIFO and FIFO_RELAXED, and the wayland backend does not support switching presentation modes between MAILBOX and FIFO, the only real thing we can do is check that the presentation mode requested is one that is supported by the swapchain and is compatible with the current presentation mode. Change-Id: I8d5506e9b1a8fba079e2f9d6ee133038feb27dca Signed-off-by: Dennis Tsiang <dennis.tsiang@arm.com> Signed-off-by: Fufu Fang <fufu.fang@arm.com>
This commit is contained in:
parent
cbf6c9765c
commit
05e98f4d17
8 changed files with 155 additions and 10 deletions
|
|
@ -172,6 +172,8 @@ wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo)
|
|||
VkResult ret = VK_SUCCESS;
|
||||
const auto present_fence_info = util::find_extension<VkSwapchainPresentFenceInfoEXT>(
|
||||
VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT, present_info->pNext);
|
||||
const auto swapchain_present_mode_info = util::find_extension<VkSwapchainPresentModeInfoEXT>(
|
||||
VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT, present_info->pNext);
|
||||
for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i)
|
||||
{
|
||||
VkSwapchainKHR swapc = pPresentInfo->pSwapchains[i];
|
||||
|
|
@ -179,9 +181,15 @@ wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo)
|
|||
auto *sc = reinterpret_cast<wsi::swapchain_base *>(swapc);
|
||||
assert(sc != nullptr);
|
||||
|
||||
const VkFence present_fence = (present_fence_info == nullptr) ? VK_NULL_HANDLE : present_fence_info->pFences[i];
|
||||
wsi::swapchain_presentation_parameters present_params;
|
||||
present_params.present_fence = (present_fence_info == nullptr) ? VK_NULL_HANDLE : present_fence_info->pFences[i];
|
||||
if (swapchain_present_mode_info != nullptr)
|
||||
{
|
||||
present_params.switch_presentation_mode = true;
|
||||
present_params.present_mode = swapchain_present_mode_info->pPresentModes[i];
|
||||
}
|
||||
VkResult res = sc->queue_present(queue, present_info, pPresentInfo->pImageIndices[i], use_image_present_semaphore,
|
||||
present_fence);
|
||||
present_params);
|
||||
if (pPresentInfo->pResults != nullptr)
|
||||
{
|
||||
pPresentInfo->pResults[i] = res;
|
||||
|
|
|
|||
|
|
@ -208,5 +208,10 @@ void surface_properties::get_surface_present_scaling_and_gravity(
|
|||
scaling_capabilities->supportedPresentGravityY = 0;
|
||||
}
|
||||
|
||||
bool surface_properties::is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b)
|
||||
{
|
||||
return is_compatible_present_modes_common(present_mode_a, present_mode_b, present_mode_compatibilities);
|
||||
}
|
||||
|
||||
} /* namespace headless */
|
||||
} /* namespace wsi */
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ public:
|
|||
|
||||
static surface_properties &get_instance();
|
||||
|
||||
bool is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b) override;
|
||||
|
||||
private:
|
||||
/* List of supported presentation modes */
|
||||
std::array<VkPresentModeKHR, 4> supported_modes;
|
||||
|
|
|
|||
|
|
@ -121,6 +121,8 @@ public:
|
|||
virtual void get_surface_present_scaling_and_gravity(
|
||||
VkSurfacePresentScalingCapabilitiesEXT *scaling_capabilities) = 0;
|
||||
|
||||
virtual bool is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b) = 0;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Set which presentation modes are compatible with each other for a particular surface
|
||||
|
|
@ -368,4 +370,37 @@ void get_surface_present_mode_compatibility_common(
|
|||
surface_present_mode_compatibility->pPresentModes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Common function for handling checking whether a present mode is compatible with another.
|
||||
*
|
||||
* @param present_mode_a First present mode.
|
||||
* @param present_mode_b Second present mode to compare against.
|
||||
* @param present_mode_compatibilities A table containing a mapping of presentation modes and what other modes they are compatible with.
|
||||
*
|
||||
* @return true if compatible, false otherwise.
|
||||
*/
|
||||
template <std::size_t SIZE>
|
||||
bool is_compatible_present_modes_common(
|
||||
VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b,
|
||||
const std::array<present_mode_compatibility, SIZE> &present_mode_compatibilities)
|
||||
{
|
||||
auto it = std::find_if(present_mode_compatibilities.begin(), present_mode_compatibilities.end(),
|
||||
[present_mode_a](present_mode_compatibility p) { return p.present_mode == present_mode_a; });
|
||||
if (it == present_mode_compatibilities.end())
|
||||
{
|
||||
WSI_LOG_ERROR("Querying compatible presentation mode support for a presentation mode that is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const present_mode_compatibility &present_mode_comp = *it;
|
||||
auto present_mode_it =
|
||||
std::find_if(present_mode_comp.compatible_present_modes.begin(), present_mode_comp.compatible_present_modes.end(),
|
||||
[present_mode_b](VkPresentModeKHR p) { return p == present_mode_b; });
|
||||
if (present_mode_it == present_mode_comp.compatible_present_modes.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace wsi */
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ swapchain_base::swapchain_base(layer::device_private_data &dev_data, const VkAll
|
|||
, m_swapchain_images(m_allocator)
|
||||
, m_surface(VK_NULL_HANDLE)
|
||||
, m_present_mode(VK_PRESENT_MODE_IMMEDIATE_KHR)
|
||||
, m_present_modes(m_allocator)
|
||||
, m_descendant(VK_NULL_HANDLE)
|
||||
, m_ancestor(VK_NULL_HANDLE)
|
||||
, m_device(VK_NULL_HANDLE)
|
||||
|
|
@ -253,6 +254,30 @@ static VkResult handle_scaling_create_info(VkDevice device, const VkSwapchainCre
|
|||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult swapchain_base::handle_swapchain_present_modes_create_info(
|
||||
VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info)
|
||||
{
|
||||
const auto *swapchain_present_modes_create_info = util::find_extension<VkSwapchainPresentModesCreateInfoEXT>(
|
||||
VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT, swapchain_create_info->pNext);
|
||||
if (swapchain_present_modes_create_info != nullptr)
|
||||
{
|
||||
if (!m_present_modes.try_resize(swapchain_present_modes_create_info->presentModeCount))
|
||||
{
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
layer::device_private_data &device_data = layer::device_private_data::get(device);
|
||||
auto &instance = device_data.instance_data;
|
||||
wsi::surface_properties *props = wsi::get_surface_properties(instance, m_surface);
|
||||
for (uint32_t i = 0; i < swapchain_present_modes_create_info->presentModeCount; i++)
|
||||
{
|
||||
assert(
|
||||
props->is_compatible_present_modes(m_present_mode, swapchain_present_modes_create_info->pPresentModes[i]));
|
||||
m_present_modes[i] = swapchain_present_modes_create_info->pPresentModes[i];
|
||||
}
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info)
|
||||
{
|
||||
assert(device != VK_NULL_HANDLE);
|
||||
|
|
@ -264,6 +289,8 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
|
|||
|
||||
m_present_mode = swapchain_create_info->presentMode;
|
||||
|
||||
TRY(handle_swapchain_present_modes_create_info(device, swapchain_create_info));
|
||||
|
||||
#if WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN
|
||||
const auto *image_compression_control = util::find_extension<VkImageCompressionControlEXT>(
|
||||
VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT, swapchain_create_info->pNext);
|
||||
|
|
@ -639,9 +666,15 @@ VkResult swapchain_base::notify_presentation_engine(uint32_t image_index)
|
|||
}
|
||||
|
||||
VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const uint32_t image_index,
|
||||
bool use_image_present_semaphore, const VkFence present_fence)
|
||||
bool use_image_present_semaphore,
|
||||
swapchain_presentation_parameters presentation_parameters)
|
||||
{
|
||||
|
||||
if (presentation_parameters.switch_presentation_mode)
|
||||
{
|
||||
TRY(handle_switching_presentation_mode(presentation_parameters.present_mode));
|
||||
}
|
||||
|
||||
const VkSemaphore *wait_semaphores = &m_swapchain_images[image_index].present_semaphore;
|
||||
uint32_t sem_count = 1;
|
||||
if (!use_image_present_semaphore)
|
||||
|
|
@ -660,19 +693,20 @@ VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *pr
|
|||
queue_submit_semaphores semaphores = {
|
||||
wait_semaphores,
|
||||
sem_count,
|
||||
(present_fence != VK_NULL_HANDLE) ? &m_swapchain_images[image_index].present_fence_wait : nullptr,
|
||||
(present_fence != VK_NULL_HANDLE) ? 1u : 0,
|
||||
(presentation_parameters.present_fence != VK_NULL_HANDLE) ? &m_swapchain_images[image_index].present_fence_wait :
|
||||
nullptr,
|
||||
(presentation_parameters.present_fence != VK_NULL_HANDLE) ? 1u : 0,
|
||||
};
|
||||
TRY_LOG_CALL(image_set_present_payload(m_swapchain_images[image_index], queue, semaphores));
|
||||
|
||||
if (present_fence != VK_NULL_HANDLE)
|
||||
if (presentation_parameters.present_fence != VK_NULL_HANDLE)
|
||||
{
|
||||
const queue_submit_semaphores wait_semaphores = { &m_swapchain_images[image_index].present_fence_wait, 1, nullptr,
|
||||
0 };
|
||||
/*
|
||||
* Here we chain wait_semaphores with present_fence through present_fence_wait.
|
||||
*/
|
||||
TRY(sync_queue_submit(m_device_data, queue, present_fence, wait_semaphores));
|
||||
TRY(sync_queue_submit(m_device_data, queue, presentation_parameters.present_fence, wait_semaphores));
|
||||
}
|
||||
|
||||
TRY(notify_presentation_engine(image_index));
|
||||
|
|
@ -774,4 +808,14 @@ VkResult swapchain_base::is_bind_allowed(uint32_t image_index) const
|
|||
VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
VkResult swapchain_base::handle_switching_presentation_mode(VkPresentModeKHR swapchain_present_mode)
|
||||
{
|
||||
assert(m_present_modes.size() > 0);
|
||||
auto it = std::find_if(m_present_modes.begin(), m_present_modes.end(),
|
||||
[swapchain_present_mode](VkPresentModeKHR p) { return p == swapchain_present_mode; });
|
||||
assert(it != m_present_modes.end());
|
||||
m_present_mode = swapchain_present_mode;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
} /* namespace wsi */
|
||||
|
|
|
|||
|
|
@ -70,6 +70,18 @@ struct swapchain_image
|
|||
VkSemaphore present_fence_wait{ VK_NULL_HANDLE };
|
||||
};
|
||||
|
||||
struct swapchain_presentation_parameters
|
||||
{
|
||||
/* Fence supplied by the application with VkSwapchainPresentFenceInfoEXT. */
|
||||
VkFence present_fence{ VK_NULL_HANDLE };
|
||||
|
||||
/* Whether the swapchain needs to switch to a different presentation mode. */
|
||||
VkBool32 switch_presentation_mode{ false };
|
||||
|
||||
/* The presentation mode to switch to. */
|
||||
VkPresentModeKHR present_mode;
|
||||
};
|
||||
|
||||
#if WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN
|
||||
struct image_compression_control_params
|
||||
{
|
||||
|
|
@ -150,14 +162,14 @@ public:
|
|||
* and not the semaphores that come with
|
||||
* \p present_info.
|
||||
*
|
||||
* @param present_fence Fence supplied by the application with VkSwapchainPresentFenceInfoEXT.
|
||||
* @param presentation_parameters Presentation parameters.
|
||||
*
|
||||
* @return If queue submission fails returns error of vkQueueSubmit, if the
|
||||
* swapchain has a descendant who started presenting returns VK_ERROR_OUT_OF_DATE_KHR,
|
||||
* otherwise returns VK_SUCCESS.
|
||||
*/
|
||||
VkResult queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const uint32_t image_index,
|
||||
bool use_image_present_semaphore, const VkFence present_fence);
|
||||
bool use_image_present_semaphore, swapchain_presentation_parameters presentation_parameters);
|
||||
|
||||
/**
|
||||
* @brief Get the allocator
|
||||
|
|
@ -310,10 +322,15 @@ protected:
|
|||
VkSurfaceKHR m_surface;
|
||||
|
||||
/**
|
||||
* @brief present mode to use for this swapchain
|
||||
* @brief Present mode currently being used for this swapchain
|
||||
*/
|
||||
VkPresentModeKHR m_present_mode;
|
||||
|
||||
/**
|
||||
* @brief Possible presentation modes this swapchain is allowed to present with VkSwapchainPresentModesCreateInfoEXT
|
||||
*/
|
||||
util::vector<VkPresentModeKHR> m_present_modes;
|
||||
|
||||
/**
|
||||
* @brief Descendant of this swapchain.
|
||||
* Used to check whether or not a descendant of this swapchain has started
|
||||
|
|
@ -624,6 +641,33 @@ private:
|
|||
* @brief A flag to track if swapchain has started presenting.
|
||||
*/
|
||||
bool m_started_presenting;
|
||||
|
||||
/**
|
||||
* @brief Handle presentation mode switching.
|
||||
*
|
||||
* If VkSwapchainPresentModeInfoEXT is supplied as part of the pNext chain of VkPresentInfoKHR
|
||||
* then this function handles switching the swapchains(s)' presentation mode
|
||||
* to the one(s) requested in VkSwapchainPresentModeInfoEXT structure.
|
||||
*
|
||||
* @param swapchain_present_mode presentation mode to switch to.
|
||||
*
|
||||
* @return VK_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
virtual VkResult handle_switching_presentation_mode(VkPresentModeKHR swapchain_present_mode);
|
||||
|
||||
/**
|
||||
* @brief Handle VkSwapchainPresentModesCreateInfoEXT .
|
||||
*
|
||||
* If VkSwapchainPresentModesCreateInfoEXT is supplied as part of the pNext chain of VkSwapchainCreateInfoKHR
|
||||
* then this function handles setting up the presentation modes for the swapchain.
|
||||
*
|
||||
* @param device VkDevice object.
|
||||
* @param swapchain_create_info Pointer to the swapchain create info struct.
|
||||
*
|
||||
* @return VK_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
VkResult handle_swapchain_present_modes_create_info(VkDevice device,
|
||||
const VkSwapchainCreateInfoKHR *swapchain_create_info);
|
||||
};
|
||||
|
||||
} /* namespace wsi */
|
||||
|
|
|
|||
|
|
@ -411,5 +411,10 @@ void surface_properties::get_surface_present_scaling_and_gravity(
|
|||
scaling_capabilities->supportedPresentGravityY = VK_PRESENT_GRAVITY_MIN_BIT_EXT;
|
||||
}
|
||||
|
||||
bool surface_properties::is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b)
|
||||
{
|
||||
return is_compatible_present_modes_common(present_mode_a, present_mode_b, present_mode_compatibilities);
|
||||
}
|
||||
|
||||
} // namespace wayland
|
||||
} // namespace wsi
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ public:
|
|||
|
||||
bool is_surface_extension_enabled(const layer::instance_private_data &instance_data) override;
|
||||
|
||||
bool is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b) override;
|
||||
|
||||
private:
|
||||
surface_properties();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue