diff --git a/layer/present_timing.cpp b/layer/present_timing.cpp index 64f23ef..1ae9446 100644 --- a/layer/present_timing.cpp +++ b/layer/present_timing.cpp @@ -29,6 +29,7 @@ */ #include #include "wsi_layer_experimental.hpp" +#include "wsi/swapchain_base.hpp" #if VULKAN_WSI_LAYER_EXPERIMENTAL @@ -38,8 +39,9 @@ VWL_VKAPI_CALL(VkResult) wsi_layer_vkSetSwapchainPresentTimingQueueSizeEXT(VkDevice device, VkSwapchainKHR swapchain, uint32_t size) VWL_API_POST { - VkResult result = VK_SUCCESS; - return result; + assert(swapchain != VK_NULL_HANDLE); + auto *sc = reinterpret_cast(swapchain); + return sc->presentation_timing_queue_set_size(size); } /** diff --git a/layer/swapchain_api.cpp b/layer/swapchain_api.cpp index c031df0..e05fc03 100644 --- a/layer/swapchain_api.cpp +++ b/layer/swapchain_api.cpp @@ -187,10 +187,17 @@ wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT, present_info->pNext); const auto swapchain_present_mode_info = util::find_extension( VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT, present_info->pNext); +#if VULKAN_WSI_LAYER_EXPERIMENTAL + const auto present_timings_info = + util::find_extension(VK_STRUCTURE_TYPE_PRESENT_TIMINGS_INFO_EXT, present_info->pNext); + if (present_timings_info) + { + assert(present_timings_info->swapchainCount == pPresentInfo->swapchainCount); + } +#endif for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) { VkSwapchainKHR swapc = pPresentInfo->pSwapchains[i]; - auto *sc = reinterpret_cast(swapc); assert(sc != nullptr); @@ -213,6 +220,13 @@ wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) present_params.use_image_present_semaphore = use_image_present_semaphore; present_params.handle_present_frame_boundary_event = frame_boundary_event_handled; + +#if VULKAN_WSI_LAYER_EXPERIMENTAL + if (present_timings_info) + { + present_params.present_timing_info = &(present_timings_info->pTimingInfos[i]); + } +#endif VkResult res = sc->queue_present(queue, present_info, present_params); if (pPresentInfo->pResults != nullptr) { diff --git a/util/custom_allocator.hpp b/util/custom_allocator.hpp index 45c2c0d..a34164a 100644 --- a/util/custom_allocator.hpp +++ b/util/custom_allocator.hpp @@ -368,6 +368,30 @@ public: return false; } } + + /** + * @brief Like std::vector::reserve but doesn't throw on out of memory errors. + * + * @param size The new capacity of the container. Same as std::vector::reserve. + * @return true If the container was resized successfuly. + * @return false If the host has run out of memory or when there is a length error. + */ + bool try_reserve(size_t size) noexcept + { + try + { + base::reserve(size); + return true; + } + catch (std::bad_alloc &e) + { + return false; + } + catch (const std::length_error &e) + { + return false; + } + } }; } /* namespace util */ diff --git a/wsi/swapchain_base.cpp b/wsi/swapchain_base.cpp index 7f5728c..aa800d6 100644 --- a/wsi/swapchain_base.cpp +++ b/wsi/swapchain_base.cpp @@ -224,6 +224,9 @@ swapchain_base::swapchain_base(layer::device_private_data &dev_data, const VkAll , m_error_state(VK_NOT_READY) , m_started_presenting(false) , m_frame_boundary_handler(m_device_data) +#if VULKAN_WSI_LAYER_EXPERIMENTAL + , m_presentation_timing(m_allocator) +#endif { } @@ -669,6 +672,22 @@ VkResult swapchain_base::notify_presentation_engine(const pending_present_reques VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const swapchain_presentation_parameters &submit_info) { +#if VULKAN_WSI_LAYER_EXPERIMENTAL + if (submit_info.present_timing_info) + { + wsi::swapchain_presentation_entry presentation_entry = {}; + presentation_entry.present_id = submit_info.pending_present.present_id; + if ((m_presentation_timing.size()) >= m_presentation_timing.capacity()) + { + return VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT; + } + + if (!m_presentation_timing.try_push_back(presentation_entry)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } +#endif if (submit_info.switch_presentation_mode) { @@ -844,4 +863,48 @@ void swapchain_base::set_present_id(uint64_t value) } } +#if VULKAN_WSI_LAYER_EXPERIMENTAL +VkResult swapchain_base::presentation_timing_queue_set_size(size_t queue_size) +{ + if (presentation_timing_get_num_outstanding_results() > queue_size) + { + return VK_NOT_READY; + } + + util::vector presentation_timing( + util::allocator(m_allocator, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE)); + if (!presentation_timing.try_reserve(queue_size)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (auto iter : m_presentation_timing) + { + if (iter.is_outstanding) + { + if (!presentation_timing.try_push_back(iter)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + } + m_presentation_timing.swap(presentation_timing); + return VK_SUCCESS; +} + +size_t swapchain_base::presentation_timing_get_num_outstanding_results() +{ + size_t num_outstanding = 0; + + for (const auto &iter : m_presentation_timing) + { + if (iter.is_outstanding) + { + num_outstanding++; + } + } + return num_outstanding; +} +#endif + } /* namespace wsi */ diff --git a/wsi/swapchain_base.hpp b/wsi/swapchain_base.hpp index fb69e53..fe087a4 100644 --- a/wsi/swapchain_base.hpp +++ b/wsi/swapchain_base.hpp @@ -110,8 +110,29 @@ struct swapchain_presentation_parameters * to underlying layers/ICD if the feature is enabled. */ VkBool32 handle_present_frame_boundary_event{ true }; + +#if VULKAN_WSI_LAYER_EXPERIMENTAL + /** + * Pointer to the present timing info. + */ + const VkPresentTimingInfoEXT *present_timing_info{ nullptr }; +#endif }; +#if VULKAN_WSI_LAYER_EXPERIMENTAL +struct swapchain_presentation_entry +{ + /** + * Whether this entry is an outstanding result or not. + */ + bool is_outstanding{ false }; + /** + * The present id. + */ + uint64_t present_id{ 0 }; +}; +#endif + #if WSI_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN struct image_compression_control_params { @@ -274,6 +295,18 @@ public: */ VkResult is_bind_allowed(uint32_t image_index) const; +#if VULKAN_WSI_LAYER_EXPERIMENTAL + /** + * @brief Set the size for the presentation timing queue + * + * @param queue_size The new queue size to set. + * + * @return VK_SUCCESS on success, VK_ERROR_OUT_OF_HOST_MEMORY when there is not enough memory, VK_NOT_READY otherwise. + * . + */ + VkResult presentation_timing_queue_set_size(size_t queue_size); +#endif + protected: layer::device_private_data &m_device_data; @@ -710,6 +743,20 @@ private: * */ frame_boundary_handler m_frame_boundary_handler; + +#if VULKAN_WSI_LAYER_EXPERIMENTAL + /** + * @brief Queue for presentation timings. + */ + util::vector m_presentation_timing; + + /** + * @brief Get the size of the presentation timing queue + * + * @return queue size of the presentation timestamp queue. + */ + size_t presentation_timing_get_num_outstanding_results(); +#endif }; } /* namespace wsi */