mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2026-05-22 08:08:12 +02:00
Adds support for present timing on Wayland even if the compositor does not support wp_presentation. Previously, support for wp_presentation was assumed.
If the time domain used by the compositor matches one of the time domains supported by the ICD: * Advertise `VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT` in `VkPresentTimingSurfaceCapabilitiesEXT` * List `VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT` in `swapchain_time_domains` Also handles the case where neither `VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR` or `VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR` is supported for all backends. Additionally fixes the issue where Wayland protocol was not dispatched correctly which resulted in Clock_ID event not being communicated back to the layer. Signed-off-by: Alex Bates <alex.bates@arm.com> Signed-off-by: Dennis Tsiang <dennis.tsiang@arm.com> Signed-off-by: Normunds Rieksts <normunds.rieksts@arm.com>
This commit is contained in:
parent
7c71bbc214
commit
441d95f1bb
16 changed files with 290 additions and 175 deletions
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017, 2019, 2021-2022, 2024 Arm Limited.
|
||||
* Copyright (c) 2016-2017, 2019, 2021-2022, 2024-2025 Arm Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
|
|
@ -23,7 +23,10 @@
|
|||
*/
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <wsi/wsi_factory.hpp>
|
||||
#include <util/helpers.hpp>
|
||||
|
||||
#include "private_data.hpp"
|
||||
#include "surface_api.hpp"
|
||||
|
||||
|
|
@ -68,7 +71,7 @@ wsi_layer_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDe
|
|||
VK_STRUCTURE_TYPE_PRESENT_TIMING_SURFACE_CAPABILITIES_EXT, pSurfaceCapabilities);
|
||||
if (surf_caps_ext != nullptr)
|
||||
{
|
||||
props->get_present_timing_surface_caps(surf_caps_ext);
|
||||
TRY_LOG_CALL(props->get_present_timing_surface_caps(physicalDevice, surf_caps_ext));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -532,14 +532,16 @@ bool surface_properties::is_surface_extension_enabled(const layer::instance_priv
|
|||
}
|
||||
|
||||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
void surface_properties::get_present_timing_surface_caps(
|
||||
VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps)
|
||||
VkResult surface_properties::get_present_timing_surface_caps(
|
||||
VkPhysicalDevice, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps)
|
||||
{
|
||||
present_timing_surface_caps->presentTimingSupported = VK_FALSE;
|
||||
present_timing_surface_caps->presentAtAbsoluteTimeSupported = VK_FALSE;
|
||||
present_timing_surface_caps->presentAtRelativeTimeSupported = VK_FALSE;
|
||||
present_timing_surface_caps->presentStageQueries = 0;
|
||||
present_timing_surface_caps->presentStageTargets = 0;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Arm Limited.
|
||||
* Copyright (c) 2024-2025 Arm Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
|
|
@ -67,7 +67,8 @@ public:
|
|||
bool is_surface_extension_enabled(const layer::instance_private_data &instance_data) override;
|
||||
|
||||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
void get_present_timing_surface_caps(VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) override;
|
||||
VkResult get_present_timing_surface_caps(
|
||||
VkPhysicalDevice physical_device, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) override;
|
||||
#endif
|
||||
|
||||
static surface_properties &get_instance();
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <array>
|
||||
#include <cassert>
|
||||
#include <wsi/swapchain_base.hpp>
|
||||
#include <util/helpers.hpp>
|
||||
|
||||
#include "present_timing.hpp"
|
||||
|
||||
|
|
@ -552,6 +553,34 @@ bool swapchain_time_domains::add_time_domain(util::unique_ptr<swapchain_time_dom
|
|||
return false;
|
||||
}
|
||||
|
||||
VkResult check_time_domain_support(VkPhysicalDevice physical_device, std::tuple<VkTimeDomainEXT, bool> *domains,
|
||||
size_t domain_size)
|
||||
{
|
||||
auto &instance_data = layer::instance_private_data::get(physical_device);
|
||||
|
||||
uint32_t supported_domains_count = 0;
|
||||
TRY(instance_data.disp.GetPhysicalDeviceCalibrateableTimeDomainsKHR(physical_device, &supported_domains_count,
|
||||
nullptr));
|
||||
|
||||
util::allocator allocator(instance_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
util::vector<VkTimeDomainEXT> supported_domains(allocator);
|
||||
if (!supported_domains.try_resize(supported_domains_count))
|
||||
{
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
TRY(instance_data.disp.GetPhysicalDeviceCalibrateableTimeDomainsKHR(physical_device, &supported_domains_count,
|
||||
supported_domains.data()));
|
||||
for (size_t i = 0; i < domain_size; i++)
|
||||
{
|
||||
std::get<1>(domains[i]) =
|
||||
std::find(supported_domains.begin(), supported_domains.begin() + supported_domains_count,
|
||||
std::get<0>(domains[i])) != (supported_domains.begin() + supported_domains_count);
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
} /* namespace wsi */
|
||||
|
||||
#endif /* VULKAN_WSI_LAYER_EXPERIMENTAL */
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
|
||||
|
|
@ -254,7 +255,7 @@ public:
|
|||
*/
|
||||
bool add_time_domain(util::unique_ptr<swapchain_time_domain> time_domain);
|
||||
|
||||
/**
|
||||
/*
|
||||
* @brief The calibrate returns a Vulkan time domain + an offset
|
||||
*
|
||||
* @param present_stage The present stage to calibrate
|
||||
|
|
@ -292,15 +293,15 @@ public:
|
|||
*/
|
||||
WSI_DEFINE_EXTENSION(VK_EXT_PRESENT_TIMING_EXTENSION_NAME);
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
template <typename T>
|
||||
static util::unique_ptr<T> create(const util::allocator &allocator,
|
||||
std::array<util::unique_ptr<wsi::vulkan_time_domain>, N> &domains, VkDevice device,
|
||||
uint32_t num_images)
|
||||
util::unique_ptr<wsi::vulkan_time_domain> *domains, size_t domain_count,
|
||||
VkDevice device, uint32_t num_images)
|
||||
{
|
||||
auto present_timing = allocator.make_unique<T>(allocator, device, num_images);
|
||||
for (auto &domain : domains)
|
||||
for (size_t i = 0; i < domain_count; i++)
|
||||
{
|
||||
if (!present_timing->get_swapchain_time_domains().add_time_domain(std::move(domain)))
|
||||
if (!present_timing->get_swapchain_time_domains().add_time_domain(std::move(domains[i])))
|
||||
{
|
||||
WSI_LOG_ERROR("Failed to add a time domain.");
|
||||
return nullptr;
|
||||
|
|
@ -495,5 +496,17 @@ private:
|
|||
uint32_t get_num_available_results();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Check if any of the time domains are supported
|
||||
*
|
||||
* @param physical_device Physical device used for the query
|
||||
* @param domains Array of time domains. The boolean will be modified to indicate
|
||||
* whether the domain is supported.
|
||||
* @param domain_size Size of the @p domains array
|
||||
* @return Vulkan result code
|
||||
*/
|
||||
VkResult check_time_domain_support(VkPhysicalDevice physical_device, std::tuple<VkTimeDomainEXT, bool> *domains,
|
||||
size_t domain_size);
|
||||
|
||||
} /* namespace wsi */
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
#include "present_timing_handler.hpp"
|
||||
#include "layer/private_data.hpp"
|
||||
|
|
@ -40,84 +39,68 @@ wsi_ext_present_timing_headless::wsi_ext_present_timing_headless(const util::all
|
|||
: wsi::wsi_ext_present_timing(allocator, device, num_images)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @brief Queries whether the driver supports the raw monotonic clock domain.
|
||||
*
|
||||
* This function invokes vkGetPhysicalDeviceCalibrateableTimeDomainsKHR twice:
|
||||
* 1. To query the count of supported time domains.
|
||||
* 2. To retrieve the list of supported time domains.
|
||||
*
|
||||
* @param device The Vulkan logical device whose physical device is queried. Must be valid.
|
||||
* @return A std::optional<bool> with:
|
||||
* - true if VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR is supported.
|
||||
* - false if VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR is not supported.
|
||||
* - std::nullopt if the query fails (e.g., vkGetPhysicalDeviceCalibrateableTimeDomainsKHR
|
||||
* returns an error or memory allocation fails).
|
||||
*/
|
||||
static std::optional<bool> is_time_domain_clock_monotonic_raw_supported(const VkDevice &device)
|
||||
{
|
||||
auto &dev_data = layer::device_private_data::get(device);
|
||||
auto &physicalDevice = dev_data.physical_device;
|
||||
auto &instance = dev_data.instance_data;
|
||||
|
||||
uint32_t supported_domains_count = 0;
|
||||
VkResult result =
|
||||
instance.disp.GetPhysicalDeviceCalibrateableTimeDomainsKHR(physicalDevice, &supported_domains_count, nullptr);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
util::allocator allocator(instance.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
util::vector<VkTimeDomainEXT> supported_domains(allocator);
|
||||
if (!supported_domains.try_resize(supported_domains_count))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
result = instance.disp.GetPhysicalDeviceCalibrateableTimeDomainsKHR(physicalDevice, &supported_domains_count,
|
||||
supported_domains.data());
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool supported = std::find(supported_domains.begin(), supported_domains.end(),
|
||||
VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR) != supported_domains.end();
|
||||
return supported;
|
||||
}
|
||||
|
||||
util::unique_ptr<wsi_ext_present_timing_headless> wsi_ext_present_timing_headless::create(
|
||||
const VkDevice &device, const util::allocator &allocator, uint32_t num_images)
|
||||
{
|
||||
|
||||
auto &dev_data = layer::device_private_data::get(device);
|
||||
|
||||
/*
|
||||
* Select the hardware raw monotonic clock domain (unaffected by NTP or adjtime adjustments)
|
||||
* when the driver supports it; otherwise use the standard monotonic clock.
|
||||
*/
|
||||
VkTimeDomainKHR monotonic_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR;
|
||||
|
||||
auto clock_monotonic_raw_support = is_time_domain_clock_monotonic_raw_supported(device);
|
||||
if (!clock_monotonic_raw_support.has_value())
|
||||
std::array monotonic_domains = {
|
||||
std::tuple{ VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT, false },
|
||||
std::tuple{ VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT, false },
|
||||
};
|
||||
auto result =
|
||||
wsi::check_time_domain_support(dev_data.physical_device, monotonic_domains.data(), monotonic_domains.size());
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else if (clock_monotonic_raw_support.value() == false)
|
||||
|
||||
VkTimeDomainEXT monotonic_domain_to_use = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT;
|
||||
bool monotonic_time_domain_supported = false;
|
||||
for (auto [domain, supported] : monotonic_domains)
|
||||
{
|
||||
monotonic_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR;
|
||||
monotonic_domain_to_use = domain;
|
||||
if (supported)
|
||||
{
|
||||
monotonic_time_domain_supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::array<util::unique_ptr<wsi::vulkan_time_domain>, 4> time_domains_array = {
|
||||
allocator.make_unique<wsi::vulkan_time_domain>(VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT,
|
||||
VK_TIME_DOMAIN_DEVICE_KHR),
|
||||
allocator.make_unique<wsi::vulkan_time_domain>(VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT, monotonic_time_domain),
|
||||
allocator.make_unique<wsi::vulkan_time_domain>(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT,
|
||||
monotonic_time_domain),
|
||||
allocator.make_unique<wsi::vulkan_time_domain>(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT,
|
||||
monotonic_time_domain)
|
||||
};
|
||||
util::vector<util::unique_ptr<wsi::vulkan_time_domain>> domains(allocator);
|
||||
if (!domains.try_push_back(allocator.make_unique<wsi::vulkan_time_domain>(
|
||||
VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT, VK_TIME_DOMAIN_DEVICE_KHR)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return wsi_ext_present_timing::create<wsi_ext_present_timing_headless>(allocator, time_domains_array, device,
|
||||
num_images);
|
||||
if (monotonic_time_domain_supported)
|
||||
{
|
||||
if (!domains.try_push_back(allocator.make_unique<wsi::vulkan_time_domain>(VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT,
|
||||
monotonic_domain_to_use)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!domains.try_push_back(allocator.make_unique<wsi::vulkan_time_domain>(
|
||||
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT, monotonic_domain_to_use)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!domains.try_push_back(allocator.make_unique<wsi::vulkan_time_domain>(
|
||||
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT, monotonic_domain_to_use)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return wsi_ext_present_timing::create<wsi_ext_present_timing_headless>(allocator, domains.data(), domains.size(),
|
||||
device, num_images);
|
||||
}
|
||||
|
||||
VkResult wsi_ext_present_timing_headless::get_swapchain_timing_properties(
|
||||
|
|
@ -137,4 +120,5 @@ VkResult wsi_ext_present_timing_headless::get_swapchain_timing_properties(
|
|||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@
|
|||
#include "surface.hpp"
|
||||
#include "util/macros.hpp"
|
||||
|
||||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
#include "present_timing_handler.hpp"
|
||||
#endif
|
||||
|
||||
namespace wsi
|
||||
{
|
||||
namespace headless
|
||||
|
|
@ -216,18 +220,34 @@ bool surface_properties::is_compatible_present_modes(VkPresentModeKHR present_mo
|
|||
}
|
||||
|
||||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
void surface_properties::get_present_timing_surface_caps(
|
||||
VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps)
|
||||
VkResult surface_properties::get_present_timing_surface_caps(
|
||||
VkPhysicalDevice physical_device, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps)
|
||||
{
|
||||
present_timing_surface_caps->presentTimingSupported = VK_TRUE;
|
||||
present_timing_surface_caps->presentAtAbsoluteTimeSupported = VK_TRUE;
|
||||
present_timing_surface_caps->presentAtRelativeTimeSupported = VK_TRUE;
|
||||
|
||||
VkPresentStageFlagsEXT monotonic_present_stages_supported = 0;
|
||||
std::array monotonic_domains = {
|
||||
std::tuple{ VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT, false },
|
||||
std::tuple{ VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT, false },
|
||||
};
|
||||
TRY(wsi::check_time_domain_support(physical_device, monotonic_domains.data(), monotonic_domains.size()));
|
||||
|
||||
auto it_monotonic_supported = std::find_if(monotonic_domains.begin(), monotonic_domains.end(),
|
||||
[](auto &domain) { return std::get<1>(domain); });
|
||||
if (it_monotonic_supported != monotonic_domains.end())
|
||||
{
|
||||
monotonic_present_stages_supported |= VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT |
|
||||
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT |
|
||||
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT;
|
||||
}
|
||||
|
||||
present_timing_surface_caps->presentStageQueries =
|
||||
VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT | VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT |
|
||||
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT | VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT;
|
||||
present_timing_surface_caps->presentStageTargets = VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT |
|
||||
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT |
|
||||
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT;
|
||||
VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT | monotonic_present_stages_supported;
|
||||
present_timing_surface_caps->presentStageTargets = monotonic_present_stages_supported;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@ public:
|
|||
bool is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b) override;
|
||||
|
||||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
void get_present_timing_surface_caps(VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) override;
|
||||
VkResult get_present_timing_surface_caps(
|
||||
VkPhysicalDevice physical_device, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -117,7 +117,8 @@ public:
|
|||
/**
|
||||
* @brief Get the present timing surface capabilities for the specific VkSurface type.
|
||||
*/
|
||||
virtual void get_present_timing_surface_caps(VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) = 0;
|
||||
virtual VkResult get_present_timing_surface_caps(
|
||||
VkPhysicalDevice physical_device, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) = 0;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
*/
|
||||
|
||||
#include "present_timing_handler.hpp"
|
||||
#include <array>
|
||||
|
||||
wsi_ext_present_timing_wayland::wsi_ext_present_timing_wayland(const util::allocator &allocator, VkDevice device,
|
||||
uint32_t num_images)
|
||||
|
|
@ -38,18 +37,40 @@ wsi_ext_present_timing_wayland::wsi_ext_present_timing_wayland(const util::alloc
|
|||
}
|
||||
|
||||
util::unique_ptr<wsi_ext_present_timing_wayland> wsi_ext_present_timing_wayland::create(
|
||||
VkTimeDomainKHR image_first_pixel_visible_time_domain, const util::allocator &allocator, VkDevice device,
|
||||
uint32_t num_images)
|
||||
VkDevice device, const util::allocator &allocator,
|
||||
std::optional<VkTimeDomainKHR> image_first_pixel_visible_time_domain, uint32_t num_images)
|
||||
{
|
||||
std::array<util::unique_ptr<wsi::vulkan_time_domain>, 2> time_domains_array = {
|
||||
allocator.make_unique<wsi::vulkan_time_domain>(VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT,
|
||||
VK_TIME_DOMAIN_DEVICE_KHR),
|
||||
allocator.make_unique<wsi::vulkan_time_domain>(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT,
|
||||
image_first_pixel_visible_time_domain)
|
||||
};
|
||||
|
||||
return wsi_ext_present_timing::create<wsi_ext_present_timing_wayland>(allocator, time_domains_array, device,
|
||||
num_images);
|
||||
util::vector<util::unique_ptr<wsi::vulkan_time_domain>> domains(allocator);
|
||||
if (!domains.try_push_back(allocator.make_unique<wsi::vulkan_time_domain>(
|
||||
VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT, VK_TIME_DOMAIN_DEVICE_KHR)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (image_first_pixel_visible_time_domain.has_value())
|
||||
{
|
||||
std::tuple<VkTimeDomainEXT, bool> monotonic_query = { *image_first_pixel_visible_time_domain, false };
|
||||
|
||||
const layer::device_private_data &device_data = layer::device_private_data::get(device);
|
||||
auto result = wsi::check_time_domain_support(device_data.physical_device, &monotonic_query, 1);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (std::get<1>(monotonic_query))
|
||||
{
|
||||
if (!domains.try_push_back(allocator.make_unique<wsi::vulkan_time_domain>(
|
||||
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT, image_first_pixel_visible_time_domain.value())))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wsi_ext_present_timing::create<wsi_ext_present_timing_wayland>(allocator, domains.data(), domains.size(),
|
||||
device, num_images);
|
||||
}
|
||||
|
||||
VkResult wsi_ext_present_timing_wayland::get_swapchain_timing_properties(
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
|
||||
#include <wsi/extensions/present_timing.hpp>
|
||||
#include <optional>
|
||||
|
||||
/**
|
||||
* @brief Present timing extension class
|
||||
|
|
@ -41,9 +42,9 @@
|
|||
class wsi_ext_present_timing_wayland : public wsi::wsi_ext_present_timing
|
||||
{
|
||||
public:
|
||||
static util::unique_ptr<wsi_ext_present_timing_wayland> create(VkTimeDomainKHR image_first_pixel_visible_time_domain,
|
||||
const util::allocator &allocator, VkDevice device,
|
||||
uint32_t num_images);
|
||||
static util::unique_ptr<wsi_ext_present_timing_wayland> create(
|
||||
VkDevice device, const util::allocator &allocator,
|
||||
std::optional<VkTimeDomainKHR> image_first_pixel_visible_time_domain, uint32_t num_images);
|
||||
|
||||
VkResult get_swapchain_timing_properties(uint64_t &timing_properties_counter,
|
||||
VkSwapchainTimingPropertiesEXT &timing_properties) override;
|
||||
|
|
@ -55,4 +56,4 @@ private:
|
|||
friend util::allocator;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ namespace wayland
|
|||
|
||||
struct formats_vector
|
||||
{
|
||||
formats_vector(util::vector<util::drm::drm_format_pair> *format_list)
|
||||
: formats(format_list)
|
||||
{
|
||||
}
|
||||
|
||||
util::vector<util::drm::drm_format_pair> *formats{ nullptr };
|
||||
bool is_out_of_memory{ false };
|
||||
};
|
||||
|
|
@ -87,66 +92,55 @@ wp_presentation_clock_id_impl(void *data, struct wp_presentation *wp_presentatio
|
|||
} // namespace
|
||||
|
||||
/**
|
||||
* @brief Get supported formats and modifiers using the zwp_linux_dmabuf_v1 interface.
|
||||
* @brief Listener for the zwp_linux_dmabuf_v1 interface
|
||||
*/
|
||||
const zwp_linux_dmabuf_v1_listener dma_buf_listener = {
|
||||
.format = zwp_linux_dmabuf_v1_format_impl,
|
||||
.modifier = zwp_linux_dmabuf_v1_modifier_impl,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Register listener for the zwp_linux_dmabuf_v1 interface to query
|
||||
* supported formats and modifiers.
|
||||
*
|
||||
* @param[in] display The wl_display that is being used.
|
||||
* @param[in] queue The wl_event_queue set for the @p dmabuf_interface
|
||||
* @param[in] dmabuf_interface Object of the zwp_linux_dmabuf_v1 interface.
|
||||
* @param[out] supported_formats Vector which will contain the supported drm
|
||||
* formats and their modifiers.
|
||||
* @param[in] dmabuf_interface Object of the zwp_linux_dmabuf_v1 interface.
|
||||
* @param[out] drm_supported_format_query Vector which will be filled with the supported drm
|
||||
* formats and their modifiers.
|
||||
*
|
||||
* @retval VK_SUCCESS Indicates success.
|
||||
* @retval VK_ERROR_UNKNOWN Indicates one of the Wayland functions failed.
|
||||
* @retval VK_ERROR_OUT_OF_DEVICE_MEMORY Indicates the host went out of memory.
|
||||
*/
|
||||
static VkResult get_supported_formats_and_modifiers(wl_display *display, wl_event_queue *queue,
|
||||
zwp_linux_dmabuf_v1 *dmabuf_interface,
|
||||
util::vector<util::drm::drm_format_pair> &supported_formats)
|
||||
static VkResult register_supported_format_and_modifier_listener(zwp_linux_dmabuf_v1 *dmabuf_interface,
|
||||
formats_vector *drm_supported_format_query)
|
||||
{
|
||||
formats_vector drm_supported_formats;
|
||||
drm_supported_formats.formats = &supported_formats;
|
||||
|
||||
const zwp_linux_dmabuf_v1_listener dma_buf_listener = {
|
||||
.format = zwp_linux_dmabuf_v1_format_impl,
|
||||
.modifier = zwp_linux_dmabuf_v1_modifier_impl,
|
||||
};
|
||||
int res = zwp_linux_dmabuf_v1_add_listener(dmabuf_interface, &dma_buf_listener, &drm_supported_formats);
|
||||
int res = zwp_linux_dmabuf_v1_add_listener(dmabuf_interface, &dma_buf_listener, drm_supported_format_query);
|
||||
if (res < 0)
|
||||
{
|
||||
WSI_LOG_ERROR("Failed to add zwp_linux_dmabuf_v1 listener.");
|
||||
return VK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Get all modifier events. */
|
||||
res = wl_display_roundtrip_queue(display, queue);
|
||||
if (res < 0)
|
||||
{
|
||||
WSI_LOG_ERROR("Roundtrip failed.");
|
||||
return VK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (drm_supported_formats.is_out_of_memory)
|
||||
{
|
||||
WSI_LOG_ERROR("Host got out of memory.");
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the clock_id using the wp_presentation interface
|
||||
* @brief Listener for the wp_presentation interface
|
||||
*/
|
||||
const wp_presentation_listener presentation_listener = {
|
||||
.clock_id = wp_presentation_clock_id_impl,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Register listener for clock_id event for wp_presentation interface
|
||||
*
|
||||
* @param presentation_interface wp_presentation interface
|
||||
* @param clockid Clock ID pointer that will get the assigned clock_id from the event
|
||||
*
|
||||
* @retval VK_SUCCESS Indicates success.
|
||||
* @retval VK_ERROR_UNKNOWN Indicates one of the Wayland functions failed.
|
||||
*/
|
||||
static VkResult get_clock_id(wl_display *display, wl_event_queue *queue, wp_presentation *presentation_interface,
|
||||
clockid_t *clockid)
|
||||
static VkResult register_clock_id_listener(wp_presentation *presentation_interface, clockid_t *clockid)
|
||||
{
|
||||
const wp_presentation_listener presentation_listener = {
|
||||
.clock_id = wp_presentation_clock_id_impl,
|
||||
};
|
||||
|
||||
int res = wp_presentation_add_listener(presentation_interface, &presentation_listener, clockid);
|
||||
if (res < 0)
|
||||
{
|
||||
|
|
@ -154,12 +148,6 @@ static VkResult get_clock_id(wl_display *display, wl_event_queue *queue, wp_pres
|
|||
return VK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
res = wl_display_roundtrip_queue(display, queue);
|
||||
if (res < 0)
|
||||
{
|
||||
WSI_LOG_ERROR("Roundtrip failed.");
|
||||
return VK_ERROR_UNKNOWN;
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +163,7 @@ surface::surface(const init_parameters ¶ms)
|
|||
, wayland_display(params.display)
|
||||
, surface_queue(nullptr)
|
||||
, wayland_surface(params.surf)
|
||||
, supported_formats(params.allocator)
|
||||
, m_supported_formats(params.allocator)
|
||||
, properties(this, params.allocator)
|
||||
, last_frame_callback(nullptr)
|
||||
, present_pending(false)
|
||||
|
|
@ -280,12 +268,6 @@ bool surface::init()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (presentation_time_interface.get() == nullptr)
|
||||
{
|
||||
WSI_LOG_ERROR("Failed to obtain wp_presentation interface.");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto surface_sync_obj =
|
||||
zwp_linux_explicit_synchronization_v1_get_synchronization(explicit_sync_interface.get(), wayland_surface);
|
||||
if (surface_sync_obj == nullptr)
|
||||
|
|
@ -296,16 +278,33 @@ bool surface::init()
|
|||
|
||||
surface_sync_interface.reset(surface_sync_obj);
|
||||
|
||||
VkResult vk_res = get_supported_formats_and_modifiers(wayland_display, surface_queue.get(), dmabuf_interface.get(),
|
||||
supported_formats);
|
||||
VkResult vk_res = VK_SUCCESS;
|
||||
if (presentation_time_interface.get() != nullptr)
|
||||
{
|
||||
vk_res = register_clock_id_listener(presentation_time_interface.get(), &m_clockid);
|
||||
if (vk_res != VK_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
formats_vector drm_supported_formats(&m_supported_formats);
|
||||
vk_res = register_supported_format_and_modifier_listener(dmabuf_interface.get(), &drm_supported_formats);
|
||||
if (vk_res != VK_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vk_res = get_clock_id(wayland_display, surface_queue.get(), presentation_time_interface.get(), &m_clockid);
|
||||
if (vk_res != VK_SUCCESS)
|
||||
res = wl_display_roundtrip_queue(wayland_display, surface_queue.get());
|
||||
if (res < 0)
|
||||
{
|
||||
WSI_LOG_ERROR("Roundtrip failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drm_supported_formats.is_out_of_memory)
|
||||
{
|
||||
WSI_LOG_ERROR("Host got out of memory for DRM format query.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ public:
|
|||
*/
|
||||
const util::vector<util::drm::drm_format_pair> &get_formats() const
|
||||
{
|
||||
return supported_formats;
|
||||
return m_supported_formats;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -184,7 +184,7 @@ private:
|
|||
/** The native Wayland surface */
|
||||
wl_surface *wayland_surface;
|
||||
/** A list of DRM formats supported by the Wayland compositor on this surface */
|
||||
util::vector<util::drm::drm_format_pair> supported_formats;
|
||||
util::vector<util::drm::drm_format_pair> m_supported_formats;
|
||||
/** Surface properties specific to the Wayland surface. */
|
||||
surface_properties properties;
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@
|
|||
#include "util/macros.hpp"
|
||||
#include "util/helpers.hpp"
|
||||
|
||||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
#include "present_timing_handler.hpp"
|
||||
#endif
|
||||
|
||||
namespace wsi
|
||||
{
|
||||
namespace wayland
|
||||
|
|
@ -261,6 +265,7 @@ VkResult surface_properties::get_required_device_extensions(util::extension_list
|
|||
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
|
||||
VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME,
|
||||
VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME,
|
||||
VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME,
|
||||
};
|
||||
return extension_list.add(required_device_extensions.data(), required_device_extensions.size());
|
||||
}
|
||||
|
|
@ -419,15 +424,47 @@ bool surface_properties::is_compatible_present_modes(VkPresentModeKHR present_mo
|
|||
}
|
||||
|
||||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
void surface_properties::get_present_timing_surface_caps(
|
||||
VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps)
|
||||
VkResult surface_properties::get_present_timing_surface_caps(
|
||||
VkPhysicalDevice physical_device, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps)
|
||||
{
|
||||
present_timing_surface_caps->presentTimingSupported = VK_TRUE;
|
||||
present_timing_surface_caps->presentAtAbsoluteTimeSupported = VK_FALSE;
|
||||
present_timing_surface_caps->presentAtRelativeTimeSupported = VK_FALSE;
|
||||
present_timing_surface_caps->presentStageQueries =
|
||||
VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT | VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT;
|
||||
present_timing_surface_caps->presentStageQueries = VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT;
|
||||
present_timing_surface_caps->presentStageTargets = 0;
|
||||
|
||||
if (specific_surface->get_presentation_time_interface() != nullptr)
|
||||
{
|
||||
bool clock_domain_supported = true;
|
||||
VkTimeDomainKHR image_first_pixel_visible_time_domain;
|
||||
|
||||
/* Check if we can support any of the reported time domains */
|
||||
switch (specific_surface->clockid())
|
||||
{
|
||||
case CLOCK_MONOTONIC:
|
||||
image_first_pixel_visible_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR;
|
||||
break;
|
||||
case CLOCK_MONOTONIC_RAW:
|
||||
image_first_pixel_visible_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR;
|
||||
break;
|
||||
default:
|
||||
clock_domain_supported = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (clock_domain_supported)
|
||||
{
|
||||
std::tuple<VkTimeDomainEXT, bool> monotonic_query = { image_first_pixel_visible_time_domain, false };
|
||||
TRY(wsi::check_time_domain_support(physical_device, &monotonic_query, 1));
|
||||
|
||||
if (std::get<1>(monotonic_query))
|
||||
{
|
||||
present_timing_surface_caps->presentStageQueries |= VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@ public:
|
|||
bool is_compatible_present_modes(VkPresentModeKHR present_mode_a, VkPresentModeKHR present_mode_b) override;
|
||||
|
||||
#if VULKAN_WSI_LAYER_EXPERIMENTAL
|
||||
void get_present_timing_surface_caps(VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) override;
|
||||
VkResult get_present_timing_surface_caps(
|
||||
VkPhysicalDevice physical_device, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) override;
|
||||
#endif
|
||||
private:
|
||||
surface_properties();
|
||||
|
|
|
|||
|
|
@ -133,20 +133,22 @@ VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCr
|
|||
bool swapchain_support_enabled = swapchain_create_info->flags & VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT;
|
||||
if (swapchain_support_enabled)
|
||||
{
|
||||
/*
|
||||
* Default to a raw hardware-based time that is not subject to NTP adjustments or
|
||||
* the incremental adjustments performed by adjtime(3)
|
||||
*/
|
||||
VkTimeDomainKHR image_first_pixel_visible_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR;
|
||||
|
||||
if (m_wsi_surface->clockid() == CLOCK_MONOTONIC)
|
||||
std::optional<VkTimeDomainKHR> image_first_pixel_visible_time_domain;
|
||||
if (m_wsi_surface->get_presentation_time_interface() != nullptr)
|
||||
{
|
||||
image_first_pixel_visible_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR;
|
||||
switch (m_wsi_surface->clockid())
|
||||
{
|
||||
case CLOCK_MONOTONIC:
|
||||
image_first_pixel_visible_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR;
|
||||
break;
|
||||
case CLOCK_MONOTONIC_RAW:
|
||||
image_first_pixel_visible_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!add_swapchain_extension(
|
||||
|
||||
wsi_ext_present_timing_wayland::create(image_first_pixel_visible_time_domain, m_allocator, m_device,
|
||||
swapchain_create_info->minImageCount)))
|
||||
if (!add_swapchain_extension(wsi_ext_present_timing_wayland::create(
|
||||
m_device, m_allocator, image_first_pixel_visible_time_domain, swapchain_create_info->minImageCount)))
|
||||
{
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue