diff --git a/CMakeLists.txt b/CMakeLists.txt index 31002d0..3b1d20b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,10 @@ if(BUILD_WSI_WAYLAND) wsi/wayland/wl_helpers.cpp wsi/wayland/swapchain.cpp) + if(VULKAN_WSI_LAYER_EXPERIMENTAL) + target_sources(wayland_wsi PRIVATE wsi/wayland/present_timing_handler.cpp) + endif() + pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client) message(STATUS "Using Wayland client include directories: ${WAYLAND_CLIENT_INCLUDE_DIRS}") message(STATUS "Using Wayland client cflags: ${WAYLAND_CLIENT_CFLAGS}") @@ -209,6 +213,10 @@ if(BUILD_WSI_HEADLESS) wsi/headless/surface.cpp wsi/headless/swapchain.cpp) + if(VULKAN_WSI_LAYER_EXPERIMENTAL) + target_sources(wsi_headless PRIVATE wsi/headless/present_timing_handler.cpp) + endif() + target_include_directories(wsi_headless PRIVATE ${PROJECT_SOURCE_DIR} ${VULKAN_CXX_INCLUDE} diff --git a/layer/present_timing_api.cpp b/layer/present_timing_api.cpp index c049def..e9ed2d0 100644 --- a/layer/present_timing_api.cpp +++ b/layer/present_timing_api.cpp @@ -41,11 +41,17 @@ VWL_VKAPI_CALL(VkResult) wsi_layer_vkSetSwapchainPresentTimingQueueSizeEXT(VkDevice device, VkSwapchainKHR swapchain, uint32_t size) VWL_API_POST { - UNUSED(device); assert(swapchain != VK_NULL_HANDLE); - auto *sc = reinterpret_cast(swapchain); + auto &device_data = layer::device_private_data::get(device); + if (!device_data.layer_owns_swapchain(swapchain)) + { + return device_data.disp.SetSwapchainPresentTimingQueueSizeEXT(device, swapchain, size); + } + + auto *sc = reinterpret_cast(swapchain); auto *ext = sc->get_swapchain_extension(true); + return ext->present_timing_queue_set_size(size); } @@ -57,12 +63,19 @@ wsi_layer_vkGetSwapchainTimingPropertiesEXT(VkDevice device, VkSwapchainKHR swap uint64_t *pSwapchainTimingPropertiesCounter, VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties) VWL_API_POST { - UNUSED(device); - UNUSED(swapchain); - UNUSED(pSwapchainTimingPropertiesCounter); - UNUSED(pSwapchainTimingProperties); - VkResult result = VK_SUCCESS; - return result; + assert(swapchain != VK_NULL_HANDLE); + + auto &device_data = layer::device_private_data::get(device); + if (!device_data.layer_owns_swapchain(swapchain)) + { + return device_data.disp.GetSwapchainTimingPropertiesEXT(device, swapchain, pSwapchainTimingPropertiesCounter, + pSwapchainTimingProperties); + } + + auto *sc = reinterpret_cast(swapchain); + auto *ext = sc->get_swapchain_extension(true); + + return ext->get_swapchain_timing_properties(*pSwapchainTimingPropertiesCounter, *pSwapchainTimingProperties); } /** diff --git a/layer/private_data.cpp b/layer/private_data.cpp index d1855e0..f77f606 100644 --- a/layer/private_data.cpp +++ b/layer/private_data.cpp @@ -51,10 +51,6 @@ VkResult instance_dispatch_table::populate(VkInstance instance, PFN_vkGetInstanc { "vk" #name, ext_name, nullptr, api_version, false, required }, INSTANCE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY) #undef DISPATCH_TABLE_ENTRY -#if VULKAN_WSI_LAYER_EXPERIMENTAL - { "GetSwapchainTimeDomainPropertiesEXT", VK_EXT_PRESENT_TIMING_EXTENSION_NAME, nullptr, API_VERSION_MAX, false, - false } -#endif /* VULKAN_WSI_LAYER_EXPERIMENTAL */ }; static constexpr auto num_entrypoints = std::distance(std::begin(entrypoints_init), std::end(entrypoints_init)); diff --git a/layer/private_data.hpp b/layer/private_data.hpp index 06198e1..0c93a56 100644 --- a/layer/private_data.hpp +++ b/layer/private_data.hpp @@ -340,6 +340,19 @@ private: * api_version: Vulkan API version where the entrypoint is part of the core specification, or API_VERSION_MAX. * required: Boolean to indicate whether the entrypoint is required by the WSI layer or optional. */ + +#if VULKAN_WSI_LAYER_EXPERIMENTAL +#define DEVICE_ENTRYPOINTS_LIST_EXPERIMENTAL(EP) \ + 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(SetSwapchainPresentTimingQueueSizeEXT, VK_EXT_PRESENT_TIMING_EXTENSION_NAME, API_VERSION_MAX, false) +#else +#define DEVICE_ENTRYPOINTS_LIST_EXPERIMENTAL(EP) +#endif + +/* Define a list of custom entrypoints that might rely on preprocessor conditions and similar */ +#define DEVICE_ENTRYPOINTS_LIST_EXPANSION(EP) DEVICE_ENTRYPOINTS_LIST_EXPERIMENTAL(EP) + #define DEVICE_ENTRYPOINTS_LIST(EP) \ /* Vulkan 1.0 */ \ EP(GetDeviceProcAddr, "", VK_API_VERSION_1_0, true) \ @@ -403,7 +416,9 @@ private: EP(GetBufferMemoryRequirements2KHR, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_API_VERSION_1_1, false) \ EP(GetImageSparseMemoryRequirements2KHR, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_API_VERSION_1_1, \ false) \ - EP(ReleaseSwapchainImagesEXT, VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, VK_API_VERSION_1_1, false) + EP(ReleaseSwapchainImagesEXT, VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, VK_API_VERSION_1_1, false) \ + /* Custom entrypoints */ \ + DEVICE_ENTRYPOINTS_LIST_EXPANSION(EP) /** * @brief Struct representing the device dispatch table. @@ -459,15 +474,6 @@ public: DEVICE_ENTRYPOINTS_LIST(DISPATCH_TABLE_SHORTCUT) #undef DISPATCH_TABLE_SHORTCUT -#if VULKAN_WSI_LAYER_EXPERIMENTAL - template - auto GetSwapchainTimeDomainPropertiesEXT(Args &&...args) const - { - return call_fn("vkGetSwapchainTimeDomainPropertiesEXT", - std::forward(args)...); - }; -#endif - private: /** * @brief Construct instance dispatch table object diff --git a/layer/wsi_layer_experimental.hpp b/layer/wsi_layer_experimental.hpp index 43d29bd..c013e77 100644 --- a/layer/wsi_layer_experimental.hpp +++ b/layer/wsi_layer_experimental.hpp @@ -174,6 +174,13 @@ typedef VkResult(VKAPI_PTR *PFN_vkGetSwapchainTimeDomainPropertiesEXT)( VkDevice device, VkSwapchainKHR swapchain, uint64_t *pTimeDomainsCounter, VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties); +typedef VkResult(VKAPI_PTR *PFN_vkGetSwapchainTimingPropertiesEXT)( + VkDevice device, VkSwapchainKHR swapchain, uint64_t *pSwapchainTimingPropertiesCounter, + VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties); + +typedef VkResult(VKAPI_PTR *PFN_vkSetSwapchainPresentTimingQueueSizeEXT)(VkDevice device, VkSwapchainKHR swapchain, + uint32_t size); + VWL_VKAPI_CALL(VkResult) wsi_layer_vkSetSwapchainPresentTimingQueueSizeEXT(VkDevice device, VkSwapchainKHR swapchain, uint32_t size) VWL_API_POST; diff --git a/wsi/extensions/present_timing.hpp b/wsi/extensions/present_timing.hpp index 6d98c5e..1392f05 100644 --- a/wsi/extensions/present_timing.hpp +++ b/wsi/extensions/present_timing.hpp @@ -243,6 +243,17 @@ public: */ swapchain_time_domains &get_swapchain_time_domains(); + /** + * @brief Backend specific implementation of the vkGetSwapchainTimingPropertiesEXT + * entrypoint. + * + * @param timing_properties_counter Timing properties counter. + * @param timing_properties Timing properties. + * @return Vulkan result code. + */ + virtual VkResult get_swapchain_timing_properties(uint64_t &timing_properties_counter, + VkSwapchainTimingPropertiesEXT &timing_properties) = 0; + protected: /** * @brief User provided memory allocation callbacks. diff --git a/wsi/headless/present_timing_handler.cpp b/wsi/headless/present_timing_handler.cpp new file mode 100644 index 0000000..8089369 --- /dev/null +++ b/wsi/headless/present_timing_handler.cpp @@ -0,0 +1,67 @@ +/* + * 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_timing.cpp + * + * @brief Contains the functionality to implement features for present timing extension. + */ + +#include "present_timing_handler.hpp" +#include + +wsi_ext_present_timing_headless::wsi_ext_present_timing_headless(const util::allocator &allocator) + : wsi::wsi_ext_present_timing(allocator) +{ +} + +util::unique_ptr wsi_ext_present_timing_headless::create( + const util::allocator &allocator) +{ + std::array, 4> time_domains_array = { + allocator.make_unique(VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT, + VK_TIME_DOMAIN_DEVICE_KHR), + allocator.make_unique(VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR), + allocator.make_unique(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR), + allocator.make_unique(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR) + }; + + return wsi_ext_present_timing::create(allocator, time_domains_array); +} + +VkResult wsi_ext_present_timing_headless::get_swapchain_timing_properties( + uint64_t &timing_properties_counter, VkSwapchainTimingPropertiesEXT &timing_properties) +{ + /* Use a reasonable approximate (5ms) that most devices should be able to match. */ + const uint64_t fixed_refresh_duration_ns = 5e+6; + + timing_properties_counter = 1; + timing_properties.refreshDuration = fixed_refresh_duration_ns; + timing_properties.variableRefreshDelay = UINT64_MAX; + + return VK_SUCCESS; +} diff --git a/wsi/headless/present_timing_handler.hpp b/wsi/headless/present_timing_handler.hpp new file mode 100644 index 0000000..37a0deb --- /dev/null +++ b/wsi/headless/present_timing_handler.hpp @@ -0,0 +1,56 @@ +/* + * 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_timing_handler.hpp + * + * @brief Contains the functionality to implement features for present timing extension. + */ +#pragma once + +#if VULKAN_WSI_LAYER_EXPERIMENTAL + +#include + +/** + * @brief Present timing extension class + * + * This class implements present timing features declarations that are specific to the headless backend. + */ +class wsi_ext_present_timing_headless : public wsi::wsi_ext_present_timing +{ +public: + static util::unique_ptr create(const util::allocator &allocator); + + VkResult get_swapchain_timing_properties(uint64_t &timing_properties_counter, + VkSwapchainTimingPropertiesEXT &timing_properties) override; + +private: + wsi_ext_present_timing_headless(const util::allocator &allocator); + + /* Allow util::allocator to access the private constructor */ + friend util::allocator; +}; + +#endif \ No newline at end of file diff --git a/wsi/headless/swapchain.cpp b/wsi/headless/swapchain.cpp index e87c12e..0a484f7 100644 --- a/wsi/headless/swapchain.cpp +++ b/wsi/headless/swapchain.cpp @@ -37,11 +37,12 @@ #include #include -#include #include #include #include "util/macros.hpp" +#include "present_timing_handler.hpp" + namespace wsi { namespace headless diff --git a/wsi/headless/swapchain.hpp b/wsi/headless/swapchain.hpp index 58631bc..61744a3 100644 --- a/wsi/headless/swapchain.hpp +++ b/wsi/headless/swapchain.hpp @@ -33,7 +33,6 @@ #include #include -#include #include namespace wsi @@ -137,40 +136,5 @@ private: VkResult add_required_extensions(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info) override; }; -#if VULKAN_WSI_LAYER_EXPERIMENTAL -/** - * @brief Present timing extension class - * - * This class implements present timing features declarations that are specific to the headless backend. - */ -class wsi_ext_present_timing_headless : public wsi_ext_present_timing -{ -public: - static util::unique_ptr create(const util::allocator &allocator) - { - std::array, 4> time_domains_array = { - allocator.make_unique(VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT, - VK_TIME_DOMAIN_DEVICE_KHR), - allocator.make_unique(VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR), - allocator.make_unique(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR), - allocator.make_unique(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR) - }; - - return wsi_ext_present_timing::create(allocator, time_domains_array); - } - -private: - wsi_ext_present_timing_headless(const util::allocator &allocator) - : wsi_ext_present_timing(allocator) - { - } - - /* Allow util::allocator to access the private constructor */ - friend util::allocator; -}; -#endif } /* namespace headless */ } /* namespace wsi */ diff --git a/wsi/wayland/present_timing_handler.cpp b/wsi/wayland/present_timing_handler.cpp new file mode 100644 index 0000000..c86583a --- /dev/null +++ b/wsi/wayland/present_timing_handler.cpp @@ -0,0 +1,57 @@ +/* + * 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_timing_handler.cpp + * + * @brief Contains the functionality to implement features for present timing extension. + */ + +#include "present_timing_handler.hpp" + +wsi_ext_present_timing_wayland::wsi_ext_present_timing_wayland(const util::allocator &allocator) + : wsi_ext_present_timing(allocator) +{ +} + +util::unique_ptr wsi_ext_present_timing_wayland::create( + const util::allocator &allocator) +{ + std::array, 1> time_domains_array = { + allocator.make_unique(VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT, + VK_TIME_DOMAIN_DEVICE_KHR) + }; + + return wsi_ext_present_timing::create(allocator, time_domains_array); +} + +VkResult wsi_ext_present_timing_wayland::get_swapchain_timing_properties( + uint64_t &timing_properties_counter, VkSwapchainTimingPropertiesEXT &timing_properties) +{ + timing_properties_counter = 0; + timing_properties.refreshDuration = 0; + timing_properties.variableRefreshDelay = 0; + + return VK_SUCCESS; +} \ No newline at end of file diff --git a/wsi/wayland/present_timing_handler.hpp b/wsi/wayland/present_timing_handler.hpp new file mode 100644 index 0000000..7644c83 --- /dev/null +++ b/wsi/wayland/present_timing_handler.hpp @@ -0,0 +1,56 @@ +/* + * 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_timing_handler.hpp + * + * @brief Contains the functionality to implement features for present timing extension. + */ +#pragma once + +#if VULKAN_WSI_LAYER_EXPERIMENTAL + +#include + +/** + * @brief Present timing extension class + * + * This class implements present timing features declarations that are specific to the Wayland backend. + */ +class wsi_ext_present_timing_wayland : public wsi::wsi_ext_present_timing +{ +public: + static util::unique_ptr create(const util::allocator &allocator); + + VkResult get_swapchain_timing_properties(uint64_t &timing_properties_counter, + VkSwapchainTimingPropertiesEXT &timing_properties) override; + +private: + wsi_ext_present_timing_wayland(const util::allocator &allocator); + + /* Allow util::allocator to access the private constructor */ + friend util::allocator; +}; + +#endif \ No newline at end of file diff --git a/wsi/wayland/swapchain.cpp b/wsi/wayland/swapchain.cpp index 7643743..91cb23f 100644 --- a/wsi/wayland/swapchain.cpp +++ b/wsi/wayland/swapchain.cpp @@ -47,6 +47,8 @@ #include #include +#include "present_timing_handler.hpp" + namespace wsi { namespace wayland diff --git a/wsi/wayland/swapchain.hpp b/wsi/wayland/swapchain.hpp index 08f4489..951204b 100644 --- a/wsi/wayland/swapchain.hpp +++ b/wsi/wayland/swapchain.hpp @@ -42,7 +42,6 @@ extern "C" { #include "wl_object_owner.hpp" #include -#include namespace wsi { @@ -233,34 +232,5 @@ private: util::vector &drm_format_props); }; -#if VULKAN_WSI_LAYER_EXPERIMENTAL -/** - * @brief Present timing extension class - * - * This class implements present timing features declarations that are specific to the wayland backend. - */ -class wsi_ext_present_timing_wayland : public wsi_ext_present_timing -{ -public: - static util::unique_ptr create(const util::allocator &allocator) - { - std::array, 1> time_domains_array = { - allocator.make_unique(VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT, - VK_TIME_DOMAIN_DEVICE_KHR) - }; - - return wsi_ext_present_timing::create(allocator, time_domains_array); - } - -private: - wsi_ext_present_timing_wayland(const util::allocator &allocator) - : wsi_ext_present_timing(allocator) - { - } - - /* Allow util::allocator to access the private constructor */ - friend util::allocator; -}; -#endif } // namespace wayland } // namespace wsi