Enables the present wait extension by default - experimental flag is no longer needed.

Fixes the following issues:

* For Wayland backend, populates the presentation feedback listener with all callbacks as it is considered a fault by the protocol to not implement those
* For Wayland backend presentation feedback listener, forwards the feedback_discarded event to present ID as there could be situations where previously submitted buffers are discarded, such as when swapchains are using the MAILBOX presentation mode.
* For all swapchains, communicate critical errors back to present wait extension as otherwise, all callers waiting that are waiting on present to be delivered in vkWaitForPresentKHR call will never exit.
* Expanded the implementation in vkWaitForPresentKHR to be able to return critical swapchain errors if they have occured during the wait time.
* Fix issues in present ID where infinite waits could result in the vkWaitForPresentKHR call returning immediately due to UINT64_MAX timeout resulting in overflowing the system clock used in std::condition_variable

Change-Id: I1e475c3073c05394db259657eae1da21764a5a5c
Signed-off-by: Normunds Rieksts <normunds.rieksts@arm.com>
Signed-off-by: Alex Bates <alex.bates@arm.com>
This commit is contained in:
Normunds Rieksts 2025-06-06 16:41:12 +00:00 committed by Iason Paraskevopoulos
parent 604b1e6a17
commit cedf53a2be
19 changed files with 138 additions and 65 deletions

View file

@ -146,13 +146,13 @@ if(BUILD_WSI_WAYLAND)
wsi/wayland/surface.cpp wsi/wayland/surface.cpp
wsi/wayland/wl_helpers.cpp wsi/wayland/wl_helpers.cpp
wsi/wayland/swapchain.cpp wsi/wayland/swapchain.cpp
wsi/wayland/present_wait_wayland.cpp
wsi/swapchain_image_create_extensions/external_memory_extension.cpp) wsi/swapchain_image_create_extensions/external_memory_extension.cpp)
if(VULKAN_WSI_LAYER_EXPERIMENTAL) if(VULKAN_WSI_LAYER_EXPERIMENTAL)
target_sources(wayland_wsi PRIVATE wsi/wayland/present_id_wayland.cpp) target_sources(wayland_wsi PRIVATE wsi/wayland/present_id_wayland.cpp)
target_sources(wayland_wsi PRIVATE wsi/wayland/present_timing_handler.cpp) target_sources(wayland_wsi PRIVATE wsi/wayland/present_timing_handler.cpp)
target_sources(wayland_wsi PRIVATE wsi/wayland/wp_presentation_feedback.cpp) target_sources(wayland_wsi PRIVATE wsi/wayland/wp_presentation_feedback.cpp)
target_sources(wayland_wsi PRIVATE wsi/wayland/present_wait_wayland.cpp)
endif() endif()
pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client) pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client)
@ -229,11 +229,11 @@ if(BUILD_WSI_HEADLESS)
add_library(wsi_headless STATIC add_library(wsi_headless STATIC
wsi/headless/surface_properties.cpp wsi/headless/surface_properties.cpp
wsi/headless/surface.cpp wsi/headless/surface.cpp
wsi/headless/swapchain.cpp) wsi/headless/swapchain.cpp
wsi/headless/present_wait_headless.cpp)
if(VULKAN_WSI_LAYER_EXPERIMENTAL) if(VULKAN_WSI_LAYER_EXPERIMENTAL)
target_sources(wsi_headless PRIVATE wsi/headless/present_timing_handler.cpp) target_sources(wsi_headless PRIVATE wsi/headless/present_timing_handler.cpp)
target_sources(wsi_headless PRIVATE wsi/headless/present_wait_headless.cpp)
endif() endif()
target_include_directories(wsi_headless PRIVATE target_include_directories(wsi_headless PRIVATE
@ -255,11 +255,8 @@ if (BUILD_WSI_DISPLAY)
wsi/display/surface_properties.cpp wsi/display/surface_properties.cpp
wsi/display/swapchain.cpp wsi/display/swapchain.cpp
wsi/display/surface.cpp wsi/display/surface.cpp
wsi/swapchain_image_create_extensions/external_memory_extension.cpp) wsi/swapchain_image_create_extensions/external_memory_extension.cpp
wsi/display/present_wait_display.cpp)
if(VULKAN_WSI_LAYER_EXPERIMENTAL)
target_sources(wsi_display PRIVATE wsi/display/present_wait_display.cpp)
endif()
pkg_check_modules(LIBDRM REQUIRED libdrm) pkg_check_modules(LIBDRM REQUIRED libdrm)
message(STATUS "Using libdrm include directories: ${LIBDRM_INCLUDE_DIRS}") message(STATUS "Using libdrm include directories: ${LIBDRM_INCLUDE_DIRS}")
@ -295,6 +292,7 @@ add_library(${PROJECT_NAME} SHARED
layer/surface_api.cpp layer/surface_api.cpp
layer/swapchain_api.cpp layer/swapchain_api.cpp
layer/swapchain_maintenance_api.cpp layer/swapchain_maintenance_api.cpp
layer/present_wait_api.cpp
util/timed_semaphore.cpp util/timed_semaphore.cpp
util/custom_allocator.cpp util/custom_allocator.cpp
util/extension_list.cpp util/extension_list.cpp
@ -303,6 +301,7 @@ add_library(${PROJECT_NAME} SHARED
wsi/external_memory.cpp wsi/external_memory.cpp
wsi/extensions/image_compression_control.cpp wsi/extensions/image_compression_control.cpp
wsi/extensions/present_id.cpp wsi/extensions/present_id.cpp
wsi/extensions/present_wait.cpp
wsi/extensions/frame_boundary.cpp wsi/extensions/frame_boundary.cpp
wsi/extensions/wsi_extension.cpp wsi/extensions/wsi_extension.cpp
wsi/extensions/swapchain_maintenance.cpp wsi/extensions/swapchain_maintenance.cpp
@ -315,11 +314,9 @@ add_library(${PROJECT_NAME} SHARED
if (VULKAN_WSI_LAYER_EXPERIMENTAL) 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}/layer/present_timing_api.cpp)
target_sources(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/wsi/extensions/present_timing.cpp) target_sources(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/wsi/extensions/present_timing.cpp)
target_sources(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/layer/present_wait_api.cpp)
target_sources(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/wsi/extensions/present_wait.cpp)
add_definitions("-DVULKAN_WSI_LAYER_EXPERIMENTAL=1") add_definitions("-DVULKAN_WSI_LAYER_EXPERIMENTAL=1")
else() else()
list(APPEND JSON_COMMANDS COMMAND sed -Ei '/VK_EXT_present_timing|VK_KHR_present_wait|VK_EXT_present_mode_fifo_latest_ready/d' ${CMAKE_CURRENT_BINARY_DIR}/VkLayer_window_system_integration.json) list(APPEND JSON_COMMANDS COMMAND sed -Ei '/VK_EXT_present_timing|VK_EXT_present_mode_fifo_latest_ready/d' ${CMAKE_CURRENT_BINARY_DIR}/VkLayer_window_system_integration.json)
add_definitions("-DVULKAN_WSI_LAYER_EXPERIMENTAL=0") add_definitions("-DVULKAN_WSI_LAYER_EXPERIMENTAL=0")
endif() endif()

View file

@ -26,6 +26,7 @@ implements the following extensions:
* VK_KHR_shared_presentable_image * VK_KHR_shared_presentable_image
* VK_EXT_image_compression_control_swapchain * VK_EXT_image_compression_control_swapchain
* VK_KHR_present_id * VK_KHR_present_id
* VK_KHR_present_wait
* VK_EXT_swapchain_maintenance1 * VK_EXT_swapchain_maintenance1
## Building ## Building

View file

@ -384,14 +384,12 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic
physical_device_swapchain_maintenance1_features->swapchainMaintenance1); physical_device_swapchain_maintenance1_features->swapchainMaintenance1);
} }
#if VULKAN_WSI_LAYER_EXPERIMENTAL
auto *present_wait_features = util::find_extension<VkPhysicalDevicePresentWaitFeaturesKHR>( auto *present_wait_features = util::find_extension<VkPhysicalDevicePresentWaitFeaturesKHR>(
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR, pCreateInfo->pNext); VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR, pCreateInfo->pNext);
if (present_wait_features != nullptr) if (present_wait_features != nullptr)
{ {
device_data.set_present_wait_enabled(present_wait_features->presentWait); device_data.set_present_wait_enabled(present_wait_features->presentWait);
} }
#endif
return VK_SUCCESS; return VK_SUCCESS;
} }
@ -492,14 +490,12 @@ wsi_layer_vkGetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physical_device,
swapchain_maintenance1_features->swapchainMaintenance1 = VK_FALSE; swapchain_maintenance1_features->swapchainMaintenance1 = VK_FALSE;
} }
#if VULKAN_WSI_LAYER_EXPERIMENTAL
auto *present_wait_features = util::find_extension<VkPhysicalDevicePresentWaitFeaturesKHR>( auto *present_wait_features = util::find_extension<VkPhysicalDevicePresentWaitFeaturesKHR>(
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR, pFeatures->pNext); VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR, pFeatures->pNext);
if (present_wait_features != nullptr) if (present_wait_features != nullptr)
{ {
present_wait_features->presentWait = VK_FALSE; present_wait_features->presentWait = VK_FALSE;
} }
#endif
instance.disp.GetPhysicalDeviceFeatures2KHR(physical_device, pFeatures); instance.disp.GetPhysicalDeviceFeatures2KHR(physical_device, pFeatures);
@ -521,7 +517,6 @@ wsi_layer_vkGetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physical_device,
wsi::set_swapchain_maintenance1_state(physical_device, swapchain_maintenance1_features); wsi::set_swapchain_maintenance1_state(physical_device, swapchain_maintenance1_features);
#if VULKAN_WSI_LAYER_EXPERIMENTAL
if (present_wait_features != nullptr) if (present_wait_features != nullptr)
{ {
/* If there is an surface extension in use that is unsupported by the layer, defer to the ICD */ /* If there is an surface extension in use that is unsupported by the layer, defer to the ICD */
@ -531,6 +526,7 @@ wsi_layer_vkGetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physical_device,
} }
} }
#if VULKAN_WSI_LAYER_EXPERIMENTAL
auto *present_timing_features = util::find_extension<VkPhysicalDevicePresentTimingFeaturesEXT>( auto *present_timing_features = util::find_extension<VkPhysicalDevicePresentTimingFeaturesEXT>(
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_TIMING_FEATURES_EXT, pFeatures->pNext); VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_TIMING_FEATURES_EXT, pFeatures->pNext);
if (present_timing_features != nullptr) if (present_timing_features != nullptr)
@ -614,12 +610,10 @@ wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName) VWL_API_POS
{ {
GET_PROC_ADDR(vkReleaseSwapchainImagesEXT); GET_PROC_ADDR(vkReleaseSwapchainImagesEXT);
} }
#if VULKAN_WSI_LAYER_EXPERIMENTAL
if (layer::device_private_data::get(device).is_device_extension_enabled(VK_KHR_PRESENT_WAIT_EXTENSION_NAME)) if (layer::device_private_data::get(device).is_device_extension_enabled(VK_KHR_PRESENT_WAIT_EXTENSION_NAME))
{ {
GET_PROC_ADDR(vkWaitForPresentKHR); GET_PROC_ADDR(vkWaitForPresentKHR);
} }
#endif
return layer::device_private_data::get(device).disp.get_user_enabled_entrypoint( return layer::device_private_data::get(device).disp.get_user_enabled_entrypoint(
device, layer::device_private_data::get(device).instance_data.api_version, funcName); device, layer::device_private_data::get(device).instance_data.api_version, funcName);

View file

@ -33,8 +33,6 @@
#include "present_wait_api.hpp" #include "present_wait_api.hpp"
#if VULKAN_WSI_LAYER_EXPERIMENTAL
/** /**
* @brief Implements vkSetSwapchainPresentTimingQueueSizeEXT Vulkan entrypoint. * @brief Implements vkSetSwapchainPresentTimingQueueSizeEXT Vulkan entrypoint.
*/ */
@ -55,5 +53,3 @@ wsi_layer_vkWaitForPresentKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_
return ext->wait_for_present_id(present_id, timeout); return ext->wait_for_present_id(present_id, timeout);
} }
#endif /* VULKAN_WSI_LAYER_EXPERIMENTAL */

View file

@ -30,10 +30,6 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <util/macros.hpp> #include <util/macros.hpp>
#if VULKAN_WSI_LAYER_EXPERIMENTAL
VWL_VKAPI_CALL(VkResult) VWL_VKAPI_CALL(VkResult)
wsi_layer_vkWaitForPresentKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t present_id, wsi_layer_vkWaitForPresentKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t present_id,
uint64_t timeout) VWL_API_POST; uint64_t timeout) VWL_API_POST;
#endif /* VULKAN_WSI_LAYER_EXPERIMENTAL */

View file

@ -634,7 +634,6 @@ bool device_private_data::is_swapchain_maintenance1_enabled() const
return swapchain_maintenance1_enabled; return swapchain_maintenance1_enabled;
} }
#if VULKAN_WSI_LAYER_EXPERIMENTAL
void device_private_data::set_present_wait_enabled(bool enable) void device_private_data::set_present_wait_enabled(bool enable)
{ {
present_wait_enabled = enable; present_wait_enabled = enable;
@ -645,6 +644,7 @@ bool device_private_data::is_present_wait_enabled()
return present_wait_enabled; return present_wait_enabled;
} }
#if VULKAN_WSI_LAYER_EXPERIMENTAL
void device_private_data::set_present_mode_fifo_latest_ready_enabled(bool enable) void device_private_data::set_present_mode_fifo_latest_ready_enabled(bool enable)
{ {
present_mode_fifo_latest_ready_enabled = enable; present_mode_fifo_latest_ready_enabled = enable;

View file

@ -370,7 +370,6 @@ private:
EP(GetSwapchainTimeDomainPropertiesEXT, VK_EXT_PRESENT_TIMING_EXTENSION_NAME, API_VERSION_MAX, false, ) \ EP(GetSwapchainTimeDomainPropertiesEXT, VK_EXT_PRESENT_TIMING_EXTENSION_NAME, API_VERSION_MAX, false, ) \
EP(GetSwapchainTimingPropertiesEXT, VK_EXT_PRESENT_TIMING_EXTENSION_NAME, API_VERSION_MAX, false, ) \ EP(GetSwapchainTimingPropertiesEXT, VK_EXT_PRESENT_TIMING_EXTENSION_NAME, API_VERSION_MAX, false, ) \
EP(SetSwapchainPresentTimingQueueSizeEXT, VK_EXT_PRESENT_TIMING_EXTENSION_NAME, API_VERSION_MAX, false, ) \ EP(SetSwapchainPresentTimingQueueSizeEXT, VK_EXT_PRESENT_TIMING_EXTENSION_NAME, API_VERSION_MAX, false, ) \
EP(WaitForPresentKHR, VK_KHR_PRESENT_WAIT_EXTENSION_NAME, API_VERSION_MAX, false, ) \
EP(GetPastPresentationTimingEXT, VK_EXT_PRESENT_TIMING_EXTENSION_NAME, API_VERSION_MAX, false, ) EP(GetPastPresentationTimingEXT, VK_EXT_PRESENT_TIMING_EXTENSION_NAME, API_VERSION_MAX, false, )
#else #else
#define DEVICE_ENTRYPOINTS_LIST_EXPERIMENTAL(EP) #define DEVICE_ENTRYPOINTS_LIST_EXPERIMENTAL(EP)
@ -463,6 +462,8 @@ private:
EP(GetCalibratedTimestampsEXT, VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, API_VERSION_MAX, false, ) \ EP(GetCalibratedTimestampsEXT, VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, API_VERSION_MAX, false, ) \
/* VK_KHR_calibrated_timestamps */ \ /* VK_KHR_calibrated_timestamps */ \
EP(GetCalibratedTimestampsKHR, VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, API_VERSION_MAX, false, ) \ EP(GetCalibratedTimestampsKHR, VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, API_VERSION_MAX, false, ) \
/* VK_KHR_present_wait */ \
EP(WaitForPresentKHR, VK_KHR_PRESENT_WAIT_EXTENSION_NAME, API_VERSION_MAX, false, ) \
/* Custom entrypoints */ \ /* Custom entrypoints */ \
DEVICE_ENTRYPOINTS_LIST_EXPANSION(EP) DEVICE_ENTRYPOINTS_LIST_EXPANSION(EP)
@ -940,7 +941,6 @@ public:
*/ */
bool is_swapchain_maintenance1_enabled() const; bool is_swapchain_maintenance1_enabled() const;
#if VULKAN_WSI_LAYER_EXPERIMENTAL
/** /**
* @brief Set whether present wait feature is enabled. * @brief Set whether present wait feature is enabled.
* *
@ -954,7 +954,6 @@ public:
* @return true if supported, false otherwise. * @return true if supported, false otherwise.
*/ */
bool is_present_wait_enabled(); bool is_present_wait_enabled();
#endif
private: private:
/* Allow util::allocator to access the private constructor */ /* Allow util::allocator to access the private constructor */
@ -1013,13 +1012,13 @@ private:
*/ */
bool swapchain_maintenance1_enabled{ false }; bool swapchain_maintenance1_enabled{ false };
#if VULKAN_WSI_LAYER_EXPERIMENTAL
/** /**
* @brief Stores whether the device supports the present wait feature. * @brief Stores whether the device supports the present wait feature.
* *
*/ */
bool present_wait_enabled{ false }; bool present_wait_enabled{ false };
#if VULKAN_WSI_LAYER_EXPERIMENTAL
/** /**
* @brief Stores whether the device has enabled support for the present timing features. * @brief Stores whether the device has enabled support for the present timing features.
*/ */

View file

@ -23,7 +23,7 @@
*/ */
/** /**
* @file present_wait_headless.cpp * @file present_wait_display.cpp
* *
* @brief Contains the base class declaration for the VK_KHR_present_wait extension. * @brief Contains the base class declaration for the VK_KHR_present_wait extension.
*/ */
@ -42,8 +42,8 @@ wsi_ext_present_wait_display::wsi_ext_present_wait_display(wsi_ext_present_id &p
VkResult wsi_ext_present_wait_display::wait_for_update(uint64_t present_id, uint64_t timeout_in_ns) VkResult wsi_ext_present_wait_display::wait_for_update(uint64_t present_id, uint64_t timeout_in_ns)
{ {
return m_present_id_ext.wait_for_present_id(present_id, timeout_in_ns) ? VK_SUCCESS : VK_TIMEOUT; return m_present_id_ext.wait_for_present_id(present_id, timeout_in_ns);
} }
} /* namespace wayland */ } /* namespace display */
} /* namespace wsi */ } /* namespace wsi */

View file

@ -23,7 +23,7 @@
*/ */
/** /**
* @file present_wait_headless.hpp * @file present_wait_display.hpp
* *
* @brief Contains the base class declaration for the VK_KHR_present_wait extension. * @brief Contains the base class declaration for the VK_KHR_present_wait extension.
*/ */
@ -68,5 +68,5 @@ private:
VkResult wait_for_update(uint64_t present_id, uint64_t timeout_in_ns) override; VkResult wait_for_update(uint64_t present_id, uint64_t timeout_in_ns) override;
}; };
} /* namespace wayland */ } /* namespace display */
} /* namespace wsi */ } /* namespace wsi */

View file

@ -101,7 +101,6 @@ VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCr
} }
} }
#if VULKAN_WSI_LAYER_EXPERIMENTAL
if (m_device_data.is_present_wait_enabled()) if (m_device_data.is_present_wait_enabled())
{ {
if (!add_swapchain_extension( if (!add_swapchain_extension(
@ -110,7 +109,6 @@ VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCr
return VK_ERROR_OUT_OF_HOST_MEMORY; return VK_ERROR_OUT_OF_HOST_MEMORY;
} }
} }
#endif
return VK_SUCCESS; return VK_SUCCESS;
} }

View file

@ -41,28 +41,66 @@ void wsi_ext_present_id::mark_delivered(uint64_t present_id)
std::unique_lock lock(m_mutex); std::unique_lock lock(m_mutex);
m_last_delivered_id.store(present_id, std::memory_order_relaxed); m_last_delivered_id.store(present_id, std::memory_order_relaxed);
} }
m_present_id_changed.notify_all(); m_present_state_changed.notify_all();
} }
bool wsi_ext_present_id::wait_for_present_id(uint64_t present_id, uint64_t timeout_in_ns) void wsi_ext_present_id::set_error_state(VkResult error_code)
{
std::unique_lock lock(m_mutex);
m_error_state.store(error_code);
m_present_state_changed.notify_all();
}
VkResult wsi_ext_present_id::get_error_state()
{
return m_error_state;
}
VkResult wsi_ext_present_id::wait_for_present_id(uint64_t present_id, uint64_t timeout_in_ns)
{ {
if (m_last_delivered_id.load() >= present_id) if (m_last_delivered_id.load() >= present_id)
{ {
return VK_SUCCESS; return VK_SUCCESS;
} }
std::unique_lock lock(m_mutex);
try try
{ {
return m_present_id_changed.wait_for(lock, std::chrono::nanoseconds(timeout_in_ns), std::unique_lock lock(m_mutex);
[&]() { return m_last_delivered_id.load() >= present_id; }); if (timeout_in_ns == UINT64_MAX)
{
/* Infinite wait */
m_present_state_changed.wait(
lock, [&]() { return (m_last_delivered_id.load() >= present_id || m_error_state.load() != VK_SUCCESS); });
/* The condition can either return when present_id condition has been reached or there has been an error */
return m_error_state;
}
else
{
/* Note: With very long timeouts it is possible that the clock in condition_variable will overflow.
* This will result in wait_for immediately returning with a failed result. Considering the
* duration needed to overflow the clock, we can probably ignore this. */
bool wait_success = m_present_state_changed.wait_for(lock, std::chrono::nanoseconds(timeout_in_ns), [&]() {
return (m_last_delivered_id.load() >= present_id || m_error_state.load() != VK_SUCCESS);
});
if (!wait_success)
{
/* We timed out */
return VK_TIMEOUT;
}
/* The condition can either return when present_id condition has been reached or there has been an error */
return m_error_state;
}
} }
catch (const std::system_error &e) catch (const std::system_error &e)
{ {
WSI_LOG_ERROR("Failed to wait for conditional variable. Code: %d, message: %s\n", e.code().value(), e.what()); WSI_LOG_ERROR("Failed to wait for conditional variable. Code: %d, message: %s\n", e.code().value(), e.what());
} }
return false; /* The mutex lock has failed */
return VK_ERROR_SURFACE_LOST_KHR;
} }
uint64_t wsi_ext_present_id::get_last_delivered_present_id() const uint64_t wsi_ext_present_id::get_last_delivered_present_id() const

View file

@ -60,15 +60,32 @@ public:
*/ */
void mark_delivered(uint64_t present_id); void mark_delivered(uint64_t present_id);
/**
* @brief Sets the error state for all pending and future image requests.
* Any error state other than VK_SUCCESS will cause all current and
* future calls to vkWaitForPresentKHR to fail with @p error_code.
*
* @param error_code Vulkan error code
*/
void set_error_state(VkResult error_code);
/**
* @brief Get the current error state
*
* @return VkResult error state
*/
VkResult get_error_state();
/** /**
* @brief Waits for present ID to be above or equal to the @p value. * @brief Waits for present ID to be above or equal to the @p value.
* *
* @param value The value to wait for. * @param present_id The value to wait for.
* @param timeout_in_ns Timeout in nanoseconds. * @param timeout_in_ns Timeout in nanoseconds.
* @return true The present ID value is equal or higher than @p value * @return VK_SUCCESS The present ID value is equal or higher than @p present_id
* @return false The present ID is lower than @p value and timeout occured * and there were no errors during present.
* Any other error code to indicate a timeout or error state for the present.
*/ */
bool wait_for_present_id(uint64_t present_id, uint64_t timeout_in_ns); VkResult wait_for_present_id(uint64_t present_id, uint64_t timeout_in_ns);
/** /**
* @brief Get the last delivered present ID value. * @brief Get the last delivered present ID value.
@ -83,12 +100,17 @@ private:
std::atomic<uint64_t> m_last_delivered_id{ 0 }; std::atomic<uint64_t> m_last_delivered_id{ 0 };
/** /**
* @brief Conditional variable that notifies whenever present ID value has changed. * @brief Current error state of the swapchain
*/ */
std::condition_variable m_present_id_changed; std::atomic<VkResult> m_error_state{ VK_SUCCESS };
/** /**
* @brief Mutex for m_present_id_changed conditional variable. * @brief Conditional variable that notifies whenever present state has changed.
*/
std::condition_variable m_present_state_changed;
/**
* @brief Mutex for m_present_state_changed conditional variable.
*/ */
std::mutex m_mutex; std::mutex m_mutex;
}; };

View file

@ -41,7 +41,12 @@ wsi_ext_present_wait::wsi_ext_present_wait(wsi_ext_present_id &present_id_extens
VkResult wsi_ext_present_wait::wait_for_present_id(uint64_t present_id, uint64_t timeout_in_ns) VkResult wsi_ext_present_wait::wait_for_present_id(uint64_t present_id, uint64_t timeout_in_ns)
{ {
if (m_present_id_ext.get_last_delivered_present_id() >= present_id) VkResult error_state = m_present_id_ext.get_error_state();
if (error_state != VK_SUCCESS)
{
return error_state;
}
else if (m_present_id_ext.get_last_delivered_present_id() >= present_id)
{ {
return VK_SUCCESS; return VK_SUCCESS;
} }

View file

@ -42,8 +42,8 @@ wsi_ext_present_wait_headless::wsi_ext_present_wait_headless(wsi_ext_present_id
VkResult wsi_ext_present_wait_headless::wait_for_update(uint64_t present_id, uint64_t timeout_in_ns) VkResult wsi_ext_present_wait_headless::wait_for_update(uint64_t present_id, uint64_t timeout_in_ns)
{ {
return m_present_id_ext.wait_for_present_id(present_id, timeout_in_ns) ? VK_SUCCESS : VK_TIMEOUT; return m_present_id_ext.wait_for_present_id(present_id, timeout_in_ns);
} }
} /* namespace wayland */ } /* namespace headless */
} /* namespace wsi */ } /* namespace wsi */

View file

@ -109,7 +109,6 @@ VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCr
} }
#endif #endif
#if VULKAN_WSI_LAYER_EXPERIMENTAL
if (m_device_data.is_present_wait_enabled()) if (m_device_data.is_present_wait_enabled())
{ {
if (!add_swapchain_extension(m_allocator.make_unique<wsi_ext_present_wait_headless>( if (!add_swapchain_extension(m_allocator.make_unique<wsi_ext_present_wait_headless>(
@ -118,7 +117,6 @@ VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCr
return VK_ERROR_OUT_OF_HOST_MEMORY; return VK_ERROR_OUT_OF_HOST_MEMORY;
} }
} }
#endif
return VK_SUCCESS; return VK_SUCCESS;
} }

View file

@ -41,15 +41,17 @@
#include <util/ring_buffer.hpp> #include <util/ring_buffer.hpp>
#include <util/timed_semaphore.hpp> #include <util/timed_semaphore.hpp>
#include <util/log.hpp> #include <util/log.hpp>
#include <util/macros.hpp>
#include <layer/private_data.hpp> #include <layer/private_data.hpp>
#include "surface_properties.hpp" #include "surface_properties.hpp"
#include "synchronization.hpp" #include "synchronization.hpp"
#include "swapchain_image_creator.hpp"
#include "extensions/frame_boundary.hpp" #include "extensions/frame_boundary.hpp"
#include "extensions/wsi_extension.hpp" #include "extensions/wsi_extension.hpp"
#include "swapchain_image_creator.hpp" #include "extensions/present_id.hpp"
#include "util/macros.hpp"
namespace wsi namespace wsi
{ {
@ -630,6 +632,12 @@ protected:
void set_error_state(VkResult state) void set_error_state(VkResult state)
{ {
m_error_state = state; m_error_state = state;
auto *ext = get_swapchain_extension<wsi_ext_present_id>();
if (ext)
{
ext->set_error_state(state);
}
} }
private: private:

View file

@ -60,7 +60,12 @@ VkResult wsi_ext_present_wait_wayland::wait_for_update(uint64_t present_id, uint
do do
{ {
if (m_present_id_ext.get_last_delivered_present_id() >= present_id) VkResult error_state = m_present_id_ext.get_error_state();
if (error_state != VK_SUCCESS)
{
return error_state;
}
else if (m_present_id_ext.get_last_delivered_present_id() >= present_id)
{ {
return VK_SUCCESS; return VK_SUCCESS;
} }

View file

@ -112,7 +112,6 @@ VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCr
} }
} }
#if VULKAN_WSI_LAYER_EXPERIMENTAL
if (m_device_data.is_present_wait_enabled()) if (m_device_data.is_present_wait_enabled())
{ {
if (!add_swapchain_extension( if (!add_swapchain_extension(
@ -121,7 +120,6 @@ VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCr
return VK_ERROR_OUT_OF_HOST_MEMORY; return VK_ERROR_OUT_OF_HOST_MEMORY;
} }
} }
#endif
if (m_device_data.should_layer_handle_frame_boundary_events()) if (m_device_data.should_layer_handle_frame_boundary_events())
{ {
@ -200,13 +198,11 @@ VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKH
#endif #endif
&& (m_present_mode != VK_PRESENT_MODE_MAILBOX_KHR); && (m_present_mode != VK_PRESENT_MODE_MAILBOX_KHR);
#if VULKAN_WSI_LAYER_EXPERIMENTAL
auto present_wait = get_swapchain_extension<wsi_ext_present_wait_wayland>(); auto present_wait = get_swapchain_extension<wsi_ext_present_wait_wayland>();
if (present_wait) if (present_wait)
{ {
present_wait->set_wayland_dispatcher(m_display, m_buffer_queue); present_wait->set_wayland_dispatcher(m_display, m_buffer_queue);
} }
#endif
return VK_SUCCESS; return VK_SUCCESS;
} }

View file

@ -30,6 +30,12 @@ namespace wsi
namespace wayland namespace wayland
{ {
VWL_CAPI_CALL(void)
wp_presentation_feedback_sync_output(void *, struct wp_presentation_feedback *, struct wl_output *)
{
/* Not relevant */
}
VWL_CAPI_CALL(void) VWL_CAPI_CALL(void)
wp_presentation_feedback_presented(void *data, struct wp_presentation_feedback *, uint32_t, uint32_t, uint32_t, wp_presentation_feedback_presented(void *data, struct wp_presentation_feedback *, uint32_t, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t, uint32_t) uint32_t, uint32_t, uint32_t, uint32_t)
@ -42,10 +48,24 @@ wp_presentation_feedback_presented(void *data, struct wp_presentation_feedback *
} }
} }
VWL_CAPI_CALL(void)
wp_presentation_feedback_discarded(void *data, struct wp_presentation_feedback *)
{
/* If the presentation request has been discarded, we still want to notify that the image has reached the compositor
* as otherwise, any functions waiting on the present ID will never be notified. There is nothing more we can do
* with this request as it has been discarded. */
auto feedback_obj = reinterpret_cast<wsi::wayland::presentation_feedback *>(data);
if (feedback_obj->ext() != nullptr)
{
feedback_obj->ext()->mark_delivered(feedback_obj->present_id());
feedback_obj->ext()->remove_from_pending_present_feedback_list(feedback_obj->present_id());
}
}
static const wp_presentation_feedback_listener presentation_listener = { static const wp_presentation_feedback_listener presentation_listener = {
.sync_output = NULL, .sync_output = wp_presentation_feedback_sync_output,
.presented = wp_presentation_feedback_presented, .presented = wp_presentation_feedback_presented,
.discarded = NULL, .discarded = wp_presentation_feedback_discarded,
}; };
VkResult register_wp_presentation_feedback_listener(struct wp_presentation_feedback *wp_presentation_feedback, VkResult register_wp_presentation_feedback_listener(struct wp_presentation_feedback *wp_presentation_feedback,