diff options
author | David Harvey-Macaulay <david.harvey-macaulay@arm.com> | 2022-01-13 10:08:03 +0000 |
---|---|---|
committer | David Harvey-Macaulay <david.harvey-macaulay@arm.com> | 2022-02-08 15:27:29 +0000 |
commit | ba0684b5e0673d1c264ae4a1cc33fadda94f9775 (patch) | |
tree | 7bf34f97bba2f31175d2db9dd96a05b0eea40095 | |
parent | e78252429a0a1e5a44b1c98b85fb948c28eecba9 (diff) | |
download | vulkan-wsi-layer-ba0684b5e0673d1c264ae4a1cc33fadda94f9775.tar.gz vulkan-wsi-layer-ba0684b5e0673d1c264ae4a1cc33fadda94f9775.tar.bz2 vulkan-wsi-layer-ba0684b5e0673d1c264ae4a1cc33fadda94f9775.zip |
Mark fences and semaphores as already signalled in AcquireNextImage
The VK_KHR_external_[fence|semaphore]_fd extensions allow sync
primitives to be signalled without the use of QueueSubmit. Using these
extensions in AcquireNextImage instead of using QueueSubmit offers two
advantages: (1) there is no waiting for work to complete in the queue
before the primitives are signalled and (2) there is no data race if
the application happens to call QueueSubmit on the same queue at the
same time.
The QueueSubmit method of signalling sync primitives continues to be
used for ICDs that do not support the external FD extensions.
Signed-off-by: David Harvey-Macaulay <david.harvey-macaulay@arm.com>
Change-Id: Ib4a922d44430110e2353a4e0221e27017e72abab
-rw-r--r-- | layer/private_data.hpp | 6 | ||||
-rw-r--r-- | util/extension_list.hpp | 7 | ||||
-rw-r--r-- | util/helpers.hpp | 37 | ||||
-rw-r--r-- | wsi/swapchain_base.cpp | 58 | ||||
-rw-r--r-- | wsi/wsi_factory.cpp | 76 |
5 files changed, 147 insertions, 37 deletions
diff --git a/layer/private_data.hpp b/layer/private_data.hpp index 11fa5ce..ee43338 100644 --- a/layer/private_data.hpp +++ b/layer/private_data.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021 Arm Limited. + * Copyright (c) 2018-2022 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -136,7 +136,9 @@ struct instance_dispatch_table OPTIONAL(GetDeviceGroupSurfacePresentModesKHR) \ OPTIONAL(GetDeviceGroupPresentCapabilitiesKHR) \ OPTIONAL(AcquireNextImage2KHR) \ - OPTIONAL(GetFenceFdKHR) + OPTIONAL(GetFenceFdKHR) \ + OPTIONAL(ImportFenceFdKHR) \ + OPTIONAL(ImportSemaphoreFdKHR) struct device_dispatch_table { diff --git a/util/extension_list.hpp b/util/extension_list.hpp index 0268efa..8caecb6 100644 --- a/util/extension_list.hpp +++ b/util/extension_list.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Arm Limited. + * Copyright (c) 2019, 2021-2022 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -85,6 +85,11 @@ public: VkResult add(const extension_list &ext_list); VkResult add(const char *const *extensions, uint32_t count); + VkResult add(const char *extension) + { + return add(&extension, 1); + } + /** * @brief Perform intersection between extensions and add them to the list. * diff --git a/util/helpers.hpp b/util/helpers.hpp index 9b5932e..cbdc4e3 100644 --- a/util/helpers.hpp +++ b/util/helpers.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Arm Limited. + * Copyright (c) 2021-2022 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -32,6 +32,41 @@ #include <vulkan/vulkan.h> +/* + * Conditional return statement. This allows functions to return early for + * failing Vulkan commands with a terse syntax. + * + * Example usage: + * + * VkResult foo() + * { + * TRY(vkCommand()); + * return VK_SUCCESS; + * } + * + * The above is equivalent to: + * + * VkResult foo() + * { + * VkResult result = vkCommand(); + * if (result != VK_SUCCESS) + * { + * return result; + * } + * return VK_SUCCESS; + * } + */ +#define TRY(expression) \ + do \ + { \ + VkResult try_result = expression; \ + if (try_result != VK_SUCCESS) \ + { \ + return try_result; \ + } \ + } \ + while (0) + namespace util { template <typename T> diff --git a/wsi/swapchain_base.cpp b/wsi/swapchain_base.cpp index ab24f0b..7fbbe68 100644 --- a/wsi/swapchain_base.cpp +++ b/wsi/swapchain_base.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2021 Arm Limited. + * Copyright (c) 2017-2022 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -404,6 +404,62 @@ VkResult swapchain_base::acquire_next_image(uint64_t timeout, VkSemaphore semaph image_status_lock.unlock(); + /* Try to signal fences/semaphores with a sync FD for optimal performance. */ + if (m_device_data.disp.ImportFenceFdKHR != nullptr && + m_device_data.disp.ImportSemaphoreFdKHR != nullptr) + { + if (fence != VK_NULL_HANDLE) + { + int already_signalled_sentinel_fd = -1; + auto info = VkImportFenceFdInfoKHR{}; + { + info.sType = VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR; + info.fence = fence; + info.handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; + info.fd = already_signalled_sentinel_fd; + } + + auto result = m_device_data.disp.ImportFenceFdKHR(m_device, &info); + switch (result) + { + case VK_SUCCESS: + fence = VK_NULL_HANDLE; + break; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: + /* Leave to fallback. */ + break; + default: + return result; + } + } + + if (semaphore != VK_NULL_HANDLE) + { + int already_signalled_sentinel_fd = -1; + auto info = VkImportSemaphoreFdInfoKHR{}; + { + info.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR; + info.semaphore = semaphore; + info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; + info.fd = already_signalled_sentinel_fd; + } + + auto result = m_device_data.disp.ImportSemaphoreFdKHR(m_device, &info); + switch (result) + { + case VK_SUCCESS: + semaphore = VK_NULL_HANDLE; + break; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: + /* Leave to fallback. */ + break; + default: + return result; + } + } + } + + /* Fallback for when importing fence/semaphore sync FDs is unsupported by the ICD. */ if (VK_NULL_HANDLE != semaphore || VK_NULL_HANDLE != fence) { VkSubmitInfo submit = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; diff --git a/wsi/wsi_factory.cpp b/wsi/wsi_factory.cpp index 6d7013a..d62b1ca 100644 --- a/wsi/wsi_factory.cpp +++ b/wsi/wsi_factory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 Arm Limited. + * Copyright (c) 2019-2022 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -119,38 +119,58 @@ util::wsi_platform_set find_enabled_layer_platforms(const VkInstanceCreateInfo * return ret; } +static VkResult get_available_device_extensions(VkPhysicalDevice physical_device, + util::extension_list &available_extensions) +{ + auto &instance_data = layer::instance_private_data::get(physical_device); + util::vector<VkExtensionProperties> properties{available_extensions.get_allocator()}; + uint32_t count; + TRY(instance_data.disp.EnumerateDeviceExtensionProperties(physical_device, nullptr, &count, nullptr)); + + if (!properties.try_resize(count)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + TRY(instance_data.disp.EnumerateDeviceExtensionProperties(physical_device, nullptr, &count, properties.data())); + TRY(available_extensions.add(properties.data(), count)); + + return VK_SUCCESS; +} + VkResult add_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util::wsi_platform_set enabled_platforms, util::extension_list &extensions_to_enable) { util::allocator allocator{extensions_to_enable.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND}; - util::extension_list device_extensions{allocator}; - util::vector<VkExtensionProperties> ext_props{allocator}; - layer::instance_private_data &inst_data = layer::instance_private_data::get(phys_dev); - uint32_t count; - VkResult res = inst_data.disp.EnumerateDeviceExtensionProperties(phys_dev, nullptr, &count, nullptr); + util::extension_list available_device_extensions{allocator}; + TRY(get_available_device_extensions(phys_dev, available_device_extensions)); - if (res == VK_SUCCESS) + /* Add optional extensions independent of winsys. */ { - if (!ext_props.try_resize(count)) + const char *optional_extensions[] = { - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - res = inst_data.disp.EnumerateDeviceExtensionProperties(phys_dev, nullptr, &count, ext_props.data()); - } + VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, + VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, - if (res != VK_SUCCESS) - { - return res; - } + VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, - res = device_extensions.add(ext_props.data(), count); + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + }; - if (res != VK_SUCCESS) - { - return res; + for (auto extension : optional_extensions) + { + if (available_device_extensions.contains(extension)) + { + TRY(extensions_to_enable.add(extension)); + } + } } + layer::instance_private_data &inst_data = layer::instance_private_data::get(phys_dev); for (const auto &wsi_ext : supported_wsi_extensions) { /* Skip iterating over platforms not enabled in the instance. */ @@ -166,13 +186,8 @@ VkResult add_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util: return VK_ERROR_INITIALIZATION_FAILED; } - res = props->get_required_device_extensions(extensions_required_by_layer); - if (res != VK_SUCCESS) - { - return res; - } - - bool supported = device_extensions.contains(extensions_required_by_layer); + TRY(props->get_required_device_extensions(extensions_required_by_layer)); + bool supported = available_device_extensions.contains(extensions_required_by_layer); if (!supported) { /* Can we accept failure? The layer unconditionally advertises support for this platform and the loader uses @@ -183,12 +198,9 @@ VkResult add_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util: return VK_ERROR_INITIALIZATION_FAILED; } - res = extensions_to_enable.add(extensions_required_by_layer); - if (res != VK_SUCCESS) - { - return res; - } + TRY(extensions_to_enable.add(extensions_required_by_layer)); } + return VK_SUCCESS; } |