Use wp_presentation_feedback to update the presented ID value

This commit is contained in:
Dennis Tsiang 2025-04-01 09:27:18 +00:00 committed by Iason Paraskevopoulos
parent 0562f6c433
commit 2d1b682129
13 changed files with 403 additions and 18 deletions

View file

@ -135,7 +135,9 @@ if(BUILD_WSI_WAYLAND)
wsi/wayland/swapchain.cpp)
if(VULKAN_WSI_LAYER_EXPERIMENTAL)
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/wp_presentation_feedback.cpp)
endif()
pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2022 Arm Limited.
* Copyright (c) 2021-2022, 2025 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
@ -26,6 +26,8 @@
#include <memory>
#include <optional>
#pragma once
namespace util
{

View file

@ -609,7 +609,7 @@ void swapchain::present_image(const pending_present_request &pending_present)
if (m_device_data.is_present_id_enabled())
{
auto *ext = get_swapchain_extension<wsi_ext_present_id>(true);
ext->set_present_id(pending_present.present_id);
ext->mark_delivered(pending_present.present_id);
}
/* And release the old one. */

View file

@ -27,17 +27,18 @@
*
* @brief Contains the implementation for the VK_KHR_present_id extension.
*/
#include "present_id.hpp"
namespace wsi
{
void wsi_ext_present_id::set_present_id(uint64_t value)
void wsi_ext_present_id::mark_delivered(uint64_t present_id)
{
if (value != 0)
/* Stale reads are acceptable as we only care that the ID is increasing */
if (present_id > m_last_delivered_id.load(std::memory_order_relaxed))
{
assert(value > m_present_id);
m_present_id = value;
m_last_delivered_id.store(present_id, std::memory_order_relaxed);
}
}

View file

@ -32,6 +32,7 @@
#include <util/custom_allocator.hpp>
#include <util/macros.hpp>
#include <atomic>
#include "wsi_extension.hpp"
@ -53,17 +54,15 @@ public:
WSI_DEFINE_EXTENSION(VK_KHR_PRESENT_ID_EXTENSION_NAME);
/**
* @brief Set the present ID for the swapchain.
*
* @param value Value to set for the present_id.
* @brief Marks the given present ID delivered (i.e. its image has been displayed).
*/
void set_present_id(uint64_t value);
void mark_delivered(uint64_t present_id);
private:
/**
* @brief Current present ID for this swapchain.
* @brief Most recently delivered present ID for this swapchain.
*/
uint64_t m_present_id{ 0 };
std::atomic<uint64_t> m_last_delivered_id{ 0 };
};
} /* namespace wsi */

View file

@ -223,8 +223,9 @@ void swapchain::present_image(const pending_present_request &pending_present)
if (m_device_data.is_present_id_enabled())
{
auto *ext = get_swapchain_extension<wsi_ext_present_id>(true);
ext->set_present_id(pending_present.present_id);
ext->mark_delivered(pending_present.present_id);
}
unpresent_image(pending_present.image_index);
}

View file

@ -0,0 +1,63 @@
/*
* 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 present_id_wayland.cpp
*
* @brief Contains the functionality to implement Wayland specific features for present ID extension.
*/
#if VULKAN_WSI_LAYER_EXPERIMENTAL
#include "present_id_wayland.hpp"
namespace wsi
{
namespace wayland
{
presentation_feedback *wsi_ext_present_id_wayland::insert_into_pending_present_feedback_list(
uint64_t present_id, struct wp_presentation_feedback *feedback_obj)
{
scoped_mutex lock(m_pending_presents_lock);
bool ret = m_pending_presents.push_back(presentation_feedback(present_id, feedback_obj, this));
if (!ret)
{
return nullptr;
}
return m_pending_presents.back();
}
void wsi_ext_present_id_wayland::remove_from_pending_present_feedback_list(uint64_t present_id)
{
scoped_mutex lock(m_pending_presents_lock);
while (m_pending_presents.size() > 0 && m_pending_presents.front()->present_id() <= present_id)
{
m_pending_presents.pop_front();
}
}
} // namespace wayland
} // namespace wsi
#endif // VULKAN_WSI_LAYER_EXPERIMENTAL

View file

@ -0,0 +1,79 @@
/*
* 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 present_id_wayland.hpp
*
* @brief Contains the functionality to implement Wayland specific features for present id extension.
*/
#pragma once
#if VULKAN_WSI_LAYER_EXPERIMENTAL
#include <wsi/extensions/present_id.hpp>
#include <util/ring_buffer.hpp>
#include "surface_properties.hpp"
#include "wp_presentation_feedback.hpp"
#include <mutex>
namespace wsi
{
namespace wayland
{
/**
* @brief Present ID extension class
*
* This class implements present ID features declarations that are specific to the Wayland backend.
*/
class wsi_ext_present_id_wayland : public wsi::wsi_ext_present_id
{
public:
/**
* @brief Insert into pending present id list.
*/
presentation_feedback *insert_into_pending_present_feedback_list(uint64_t present_id,
struct wp_presentation_feedback *feedback_obj);
/**
* @brief Remove a present id from the pending present id list.
*/
void remove_from_pending_present_feedback_list(uint64_t present_id);
private:
/**
* @brief Mutex for synchronising accesses to the pending present id list.
*/
std::mutex m_pending_presents_lock;
/**
* @brief Stores the presentation feedbacks that have been queued.
*/
util::ring_buffer<presentation_feedback, wsi::surface_properties::MAX_SWAPCHAIN_IMAGE_COUNT * 2> m_pending_presents;
};
} // namespace wayland
} // namespace wsi
#endif // VULKAN_WSI_LAYER_EXPERIMENTAL

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2024 Arm Limited.
* Copyright (c) 2021-2025 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
@ -111,6 +111,17 @@ public:
return surface_sync_interface.get();
}
/**
* @brief Returns a pointer to the Wayland wp_presentation interface obtained for the wayland
* surface.
*
* The raw pointer is valid for the lifetime of the surface.
*/
struct wp_presentation *get_presentation_time_interface()
{
return presentation_time_interface.get();
}
/**
* @brief Returns a reference to a list of DRM formats supported by the Wayland surface.
*

View file

@ -44,10 +44,12 @@
#include "wl_helpers.hpp"
#include <wsi/extensions/image_compression_control.hpp>
#include <wsi/extensions/present_id.hpp>
#include <wsi/extensions/swapchain_maintenance.hpp>
#include <wsi/extensions/present_id.hpp>
#include "present_timing_handler.hpp"
#include "present_id_wayland.hpp"
#include "wp_presentation_feedback.hpp"
namespace wsi
{
@ -95,7 +97,11 @@ VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCr
if (m_device_data.is_present_id_enabled())
{
#if VULKAN_WSI_LAYER_EXPERIMENTAL
if (!add_swapchain_extension(m_allocator.make_unique<wsi_ext_present_id_wayland>()))
#else
if (!add_swapchain_extension(m_allocator.make_unique<wsi_ext_present_id>()))
#endif
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
@ -568,6 +574,28 @@ void swapchain::present_image(const pending_present_request &pending_present)
}
}
#if VULKAN_WSI_LAYER_EXPERIMENTAL
if (m_device_data.is_present_id_enabled())
{
auto *ext = get_swapchain_extension<wsi_ext_present_id_wayland>(true);
if (m_wsi_surface->get_presentation_time_interface() != nullptr)
{
wp_presentation *pres = m_wsi_surface->get_presentation_time_interface();
struct wp_presentation_feedback *feedback = wp_presentation_feedback(pres, m_wsi_surface->get_wl_surface());
wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(feedback), m_buffer_queue);
presentation_feedback *feedback_obj =
ext->insert_into_pending_present_feedback_list(pending_present.present_id, feedback);
if (feedback_obj == nullptr)
{
WSI_LOG_ERROR("Error adding to pending present feedback list");
set_error_state(VK_ERROR_SURFACE_LOST_KHR);
return;
}
register_wp_presentation_feedback_listener(feedback, feedback_obj);
}
}
#endif
wl_surface_commit(m_surface);
res = wl_display_flush(m_display);
if (res < 0)
@ -579,8 +607,15 @@ void swapchain::present_image(const pending_present_request &pending_present)
if (m_device_data.is_present_id_enabled())
{
#if VULKAN_WSI_LAYER_EXPERIMENTAL
auto *ext = get_swapchain_extension<wsi_ext_present_id_wayland>(true);
if (m_wsi_surface->get_presentation_time_interface() == nullptr)
#else
auto *ext = get_swapchain_extension<wsi_ext_present_id>(true);
ext->set_present_id(pending_present.present_id);
#endif
{
ext->mark_delivered(pending_present.present_id);
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2024 Arm Limited.
* Copyright (c) 2021-2025 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
@ -31,7 +31,7 @@
#include <linux-dmabuf-unstable-v1-client-protocol.h>
#include <linux-explicit-synchronization-unstable-v1-protocol.h>
#include <presentation-time-client-protocol.h>
#include <memory.h>
#include <memory>
#include <functional>
namespace wsi
@ -74,6 +74,11 @@ static inline void wayland_object_destroy(wl_event_queue *obj)
wl_event_queue_destroy(obj);
}
static inline void wayland_object_destroy(struct wp_presentation_feedback *obj)
{
wp_presentation_feedback_destroy(obj);
}
template <typename T>
struct wayland_deleter
{

View file

@ -0,0 +1,64 @@
/*
* 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.
*/
#include "wp_presentation_feedback.hpp"
#include "present_id_wayland.hpp"
namespace wsi
{
namespace wayland
{
VWL_CAPI_CALL(void)
wp_presentation_feedback_presented(void *data, struct wp_presentation_feedback *, uint32_t, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t, uint32_t)
{
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 = {
.sync_output = NULL,
.presented = wp_presentation_feedback_presented,
.discarded = NULL,
};
VkResult register_wp_presentation_feedback_listener(struct wp_presentation_feedback *wp_presentation_feedback,
void *data)
{
int res = wp_presentation_feedback_add_listener(wp_presentation_feedback, &presentation_listener, data);
if (res < 0)
{
WSI_LOG_ERROR("Failed to add wp_presentation_feedback listener.");
return VK_ERROR_INITIALIZATION_FAILED;
}
return VK_SUCCESS;
}
} // namespace wayland
} // namespace wsi

View file

@ -0,0 +1,123 @@
/*
* 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
* @brief Contains functions for handling the wp_presentation_feedback Wayland protocol
*/
#pragma once
#include <vulkan/vulkan.h>
#include <presentation-time-client-protocol.h>
#include "wl_object_owner.hpp"
namespace wsi
{
namespace wayland
{
class wsi_ext_present_id_wayland;
/**
* @brief Registers the listeners for wp_presentation_feedback
* @param wp_presentation_feedback - wp_presentation_feedback interface
* @param data - Data to pass to the callbacks
* @return VK_SUCCESS on success, error otherwise.
*/
VkResult register_wp_presentation_feedback_listener(struct wp_presentation_feedback *wp_presentation_feedback,
void *data);
/**
* @brief Class to hold a presentation feedback and associated attributes.
*/
class presentation_feedback
{
public:
presentation_feedback(uint64_t present_id, struct wp_presentation_feedback *feedback,
wsi_ext_present_id_wayland *ext)
: m_present_id(present_id)
, m_feedback(feedback)
, m_ext(ext)
{
}
~presentation_feedback() = default;
presentation_feedback(const presentation_feedback &feedback_obj) = delete;
presentation_feedback &operator=(const presentation_feedback &feedback_obj) = delete;
presentation_feedback(presentation_feedback &&feedback_obj)
: m_present_id(feedback_obj.m_present_id)
, m_feedback(std::move(feedback_obj.m_feedback))
, m_ext(feedback_obj.m_ext)
{
feedback_obj.reset();
}
presentation_feedback &operator=(presentation_feedback &&feedback_obj)
{
if (this == &feedback_obj)
{
return *this;
}
if (m_feedback != nullptr)
{
wp_presentation_feedback_destroy(m_feedback.get());
}
m_present_id = feedback_obj.m_present_id;
m_feedback = std::move(feedback_obj.m_feedback);
m_ext = feedback_obj.m_ext;
feedback_obj.reset();
}
void reset()
{
m_present_id = 0;
m_feedback = nullptr;
m_ext = nullptr;
}
uint64_t present_id()
{
return m_present_id;
}
struct wp_presentation_feedback *feedback()
{
return m_feedback.get();
}
wsi_ext_present_id_wayland *ext()
{
return m_ext;
}
private:
uint64_t m_present_id;
wayland_owner<struct wp_presentation_feedback> m_feedback;
wsi_ext_present_id_wayland *m_ext;
};
} // namespace wayland
} // namespace wsi