diff options
author | Matteo Franchin <matteo.franchin@arm.com> | 2022-05-17 15:18:00 +0100 |
---|---|---|
committer | Matteo Franchin <matteo.franchin@arm.com> | 2022-05-30 13:51:20 +0100 |
commit | dd1f3f24cc9ecc89ae34c435cf66da8d481af406 (patch) | |
tree | 827078665d2b9b2d7f6ba05fd9fc9bdecc676920 | |
parent | 2bc21091946a42aa56768d9bfe314ab3e232c9c8 (diff) | |
download | vulkan-wsi-layer-dd1f3f24cc9ecc89ae34c435cf66da8d481af406.tar.gz vulkan-wsi-layer-dd1f3f24cc9ecc89ae34c435cf66da8d481af406.tar.bz2 vulkan-wsi-layer-dd1f3f24cc9ecc89ae34c435cf66da8d481af406.zip |
Enable instance extensions required by layer
The layer needs functionality that is not part of Vulkan 1.0 and is
provided by either Vulkan 1.1 or separate Vulkan extensions.
The layer used to solve this issue by bumping the API version passed
by the application in VkCreateInfo to 1.1 if this was set to 1.0.
This workaround does not seem to be working anymore with recent
versions of the loader. Fortunately, the loader now allows layers
to change the extension lists passed by the application.
This patch changes the layer to use this approach and removes the
API bump logic.
Documentation is updated accordingly.
Change-Id: I61c426311612c7f288a0f7d969782d6c5365acf5
Signed-off-by: Matteo Franchin <matteo.franchin@arm.com>
-rw-r--r-- | README.md | 14 | ||||
-rw-r--r-- | layer/layer.cpp | 106 | ||||
-rw-r--r-- | layer/private_data.hpp | 68 | ||||
-rw-r--r-- | util/platform_set.hpp | 7 | ||||
-rw-r--r-- | wsi/wsi_factory.cpp | 4 |
5 files changed, 110 insertions, 89 deletions
@@ -25,14 +25,19 @@ enabled via a build option [as explained below](#building-with-wayland-support). `VK_EXT_headless_surface` extension and for the Vulkan 1.1, or later API. The Vulkan WSI Layer uses Vulkan extensions to communicate with the Vulkan ICDs. -The ICDs installed in the system are required to support the Vulkan 1.1, or -later API, and the following device extensions: -* When Wayland support is enabled: +The ICDs installed in the system are required to support the following extensions: +* Instance extensions: + * VK_KHR_get_physical_device_properties_2 + * VK_KHR_external_fence_capabilities + * VK_KHR_external_semaphore_capabilities + * VK_KHR_external_memory_capabilities +* Device extensions (only required when Wayland support is enabled): * VK_EXT_image_drm_format_modifier * VK_KHR_image_format_list * VK_EXT_external_memory_dma_buf * VK_KHR_external_memory_fd * VK_KHR_external_fence_fd +* Any dependencies of the above extensions ### Building the VulkanĀ® loader @@ -110,9 +115,6 @@ provides a generic ion implementation that may work in systems that support linear formats. This is selected by the `-DSELECT_EXTERNAL_ALLOCATOR=ion` option, as shown above. -Wayland support is still **EXPERIMENTAL**. What this means in practice is that -the support is incomplete and not ready for prime time. - ## Installation Copy the shared library `libVkLayer_window_system_integration.so` and JSON diff --git a/layer/layer.cpp b/layer/layer.cpp index b2e00ba..8eb84a6 100644 --- a/layer/layer.cpp +++ b/layer/layer.cpp @@ -25,6 +25,7 @@ #include <cassert> #include <cstdio> #include <cstring> +#include <array> #include <vulkan/vk_layer.h> #include <vulkan/vulkan.h> @@ -102,45 +103,58 @@ VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, con return VK_ERROR_INITIALIZATION_FAILED; } - /* Advance the link info for the next element on the chain. */ - layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext; + /* For instances handled by the layer, we need to enable extra extensions, therefore take a copy of pCreateInfo. */ + VkInstanceCreateInfo modified_info = *pCreateInfo; - /* The layer needs some Vulkan 1.1 functionality in order to operate correctly. - * We thus change the application info to require this API version, if necessary. - * This may have consequences for ICDs whose behaviour depends on apiVersion. + /* Create a util::vector in case we need to modify the modified_info.ppEnabledExtensionNames list. + * This object and the extension_list object need to be in the global scope so they can be alive by the time + * vkCreateInstance is called. */ - const uint32_t minimum_required_vulkan_version = VK_API_VERSION_1_1; - VkApplicationInfo modified_app_info{}; - if (nullptr != pCreateInfo->pApplicationInfo) + util::allocator allocator{VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, pAllocator}; + util::vector<const char *> modified_enabled_extensions{allocator}; + util::extension_list extensions{allocator}; + + /* Find all the platforms that the layer can handle based on pCreateInfo->ppEnabledExtensionNames. */ + auto layer_platforms_to_enable = wsi::find_enabled_layer_platforms(pCreateInfo); + if (!layer_platforms_to_enable.empty()) { - modified_app_info = *pCreateInfo->pApplicationInfo; - if (modified_app_info.apiVersion < minimum_required_vulkan_version) + /* Create a list of extensions to enable, including the provided extensions and those required by the layer. */ + TRY(extensions.add(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount)); + + if (!extensions.contains(VK_KHR_SURFACE_EXTENSION_NAME)) { - modified_app_info.apiVersion = minimum_required_vulkan_version; + return VK_ERROR_EXTENSION_NOT_PRESENT; } - } - else - { - modified_app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - modified_app_info.apiVersion = minimum_required_vulkan_version; + + /* The extensions listed below are those strictly required by the layer. Other extensions may be used by the + * layer (such as calling their entrypoints), when they are enabled by the application. + */ + std::array<const char*, 4> extra_extensions = { + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, + /* The extension below is only needed for Wayland. For now, enable it also for headless. */ + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, + }; + TRY(extensions.add(extra_extensions.data(), extra_extensions.size())); + TRY(extensions.get_extension_strings(modified_enabled_extensions)); + + modified_info.ppEnabledExtensionNames = modified_enabled_extensions.data(); + modified_info.enabledExtensionCount = modified_enabled_extensions.size(); } - VkInstanceCreateInfo modified_info = *pCreateInfo; - modified_info.pApplicationInfo = &modified_app_info; + /* Advance the link info for the next element on the chain. */ + layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext; /* Now call create instance on the chain further down the list. * Note that we do not remove the extensions that the layer supports from modified_info.ppEnabledExtensionNames. * Layers have to abide the rule that vkCreateInstance must not generate an error for unrecognized extension names. * Also, the loader filters the extension list to ensure that ICDs do not see extensions that they do not support. */ - VkResult result; - result = fpCreateInstance(&modified_info, pAllocator, pInstance); - if (result != VK_SUCCESS) - { - return result; - } + TRY(fpCreateInstance(&modified_info, pAllocator, pInstance)); instance_dispatch_table table{}; + VkResult result; result = table.populate(*pInstance, fpGetInstanceProcAddr); if (result != VK_SUCCESS) { @@ -151,9 +165,6 @@ VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, con return result; } - /* Find all the platforms that the layer can handle based on pCreateInfo->ppEnabledExtensionNames. */ - auto layer_platforms_to_enable = wsi::find_enabled_layer_platforms(pCreateInfo); - /* Following the spec: use the callbacks provided to vkCreateInstance() if not nullptr, * otherwise use the default callbacks. */ @@ -214,45 +225,30 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic /* Advance the link info for the next element on the chain. */ layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext; - /* Copy the extension to a util::extension_list. */ - auto &inst_data = instance_private_data::get(physicalDevice); + /* Enable extra extensions if needed by the layer, similarly to what done in vkCreateInstance. */ + VkDeviceCreateInfo modified_info = *pCreateInfo; + auto &inst_data = instance_private_data::get(physicalDevice); util::allocator allocator{inst_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, pAllocator}; + util::vector<const char *> modified_enabled_extensions{allocator}; util::extension_list enabled_extensions{allocator}; - VkResult result; - result = enabled_extensions.add(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount); - if (result != VK_SUCCESS) - { - return result; - } - /* Add the extensions required by the platforms that are being enabled in the layer. */ const util::wsi_platform_set& enabled_platforms = inst_data.get_enabled_platforms(); - result = wsi::add_extensions_required_by_layer(physicalDevice, enabled_platforms, enabled_extensions); - if (result != VK_SUCCESS) + if (!enabled_platforms.empty()) { - return result; - } + TRY(enabled_extensions.add(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount)); + TRY(wsi::add_extensions_required_by_layer(physicalDevice, enabled_platforms, enabled_extensions)); + TRY(enabled_extensions.get_extension_strings(modified_enabled_extensions)); - util::vector<const char *> modified_enabled_extensions{allocator}; - result = enabled_extensions.get_extension_strings(modified_enabled_extensions); - if (result != VK_SUCCESS) - { - return result; + modified_info.ppEnabledExtensionNames = modified_enabled_extensions.data(); + modified_info.enabledExtensionCount = modified_enabled_extensions.size(); } /* Now call create device on the chain further down the list. */ - VkDeviceCreateInfo modified_info = *pCreateInfo; - modified_info.ppEnabledExtensionNames = modified_enabled_extensions.data(); - modified_info.enabledExtensionCount = modified_enabled_extensions.size(); - result = fpCreateDevice(physicalDevice, &modified_info, pAllocator, pDevice); - if (result != VK_SUCCESS) - { - return result; - } + TRY(fpCreateDevice(physicalDevice, &modified_info, pAllocator, pDevice)); device_dispatch_table table{}; - result = table.populate(*pDevice, fpGetDeviceProcAddr); + VkResult result = table.populate(*pDevice, fpGetDeviceProcAddr); if (result != VK_SUCCESS) { if (table.DestroyDevice != nullptr) @@ -265,7 +261,7 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic /* Following the spec: use the callbacks provided to vkCreateDevice() if not nullptr, otherwise use the callbacks * provided to the instance (if no allocator callbacks was provided to the instance, it will use default ones). */ - util::allocator device_allocator{ inst_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE, pAllocator }; + util::allocator device_allocator{inst_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE, pAllocator}; result = device_private_data::associate(*pDevice, inst_data, physicalDevice, table, loader_callback, device_allocator); if (result != VK_SUCCESS) diff --git a/layer/private_data.hpp b/layer/private_data.hpp index 60c548d..048aee4 100644 --- a/layer/private_data.hpp +++ b/layer/private_data.hpp @@ -56,26 +56,37 @@ namespace layer * guarantee than we can safely call them. We still mark the entrypoints with REQUIRED() and OPTIONAL(). The layer * fails if vkGetInstanceProcAddr returns null for entrypoints that are REQUIRED(). */ -#define INSTANCE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \ - REQUIRED(GetInstanceProcAddr) \ - REQUIRED(DestroyInstance) \ - REQUIRED(GetPhysicalDeviceProperties) \ - REQUIRED(GetPhysicalDeviceImageFormatProperties) \ - REQUIRED(EnumerateDeviceExtensionProperties) \ - OPTIONAL(GetPhysicalDeviceSurfaceCapabilitiesKHR) \ - OPTIONAL(GetPhysicalDeviceSurfaceCapabilities2KHR) \ - OPTIONAL(GetPhysicalDeviceSurfaceFormatsKHR) \ - OPTIONAL(GetPhysicalDeviceSurfaceFormats2KHR) \ - OPTIONAL(GetPhysicalDeviceSurfacePresentModesKHR) \ - OPTIONAL(GetPhysicalDeviceSurfaceSupportKHR) \ - OPTIONAL(CreateHeadlessSurfaceEXT) \ - OPTIONAL(CreateWaylandSurfaceKHR) \ - OPTIONAL(DestroySurfaceKHR) \ - OPTIONAL(GetPhysicalDeviceImageFormatProperties2KHR) \ - OPTIONAL(GetPhysicalDeviceFormatProperties2KHR) \ - OPTIONAL(GetPhysicalDevicePresentRectanglesKHR) \ - OPTIONAL(GetPhysicalDeviceExternalFencePropertiesKHR)\ - OPTIONAL(GetPhysicalDeviceFeatures2KHR) +#define INSTANCE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \ + /* Vulkan 1.0 */ \ + REQUIRED(GetInstanceProcAddr) \ + REQUIRED(DestroyInstance) \ + REQUIRED(GetPhysicalDeviceProperties) \ + REQUIRED(GetPhysicalDeviceImageFormatProperties) \ + REQUIRED(EnumerateDeviceExtensionProperties) \ + /* VK_KHR_surface */ \ + OPTIONAL(DestroySurfaceKHR) \ + OPTIONAL(GetPhysicalDeviceSurfaceCapabilitiesKHR) \ + OPTIONAL(GetPhysicalDeviceSurfaceFormatsKHR) \ + OPTIONAL(GetPhysicalDeviceSurfacePresentModesKHR) \ + OPTIONAL(GetPhysicalDeviceSurfaceSupportKHR) \ + /* VK_EXT_headless_surface */ \ + OPTIONAL(CreateHeadlessSurfaceEXT) \ + /* VK_KHR_wayland_surface */ \ + OPTIONAL(CreateWaylandSurfaceKHR) \ + /* VK_KHR_get_surface_capabilities2 */ \ + OPTIONAL(GetPhysicalDeviceSurfaceCapabilities2KHR) \ + OPTIONAL(GetPhysicalDeviceSurfaceFormats2KHR) \ + /* VK_KHR_get_physical_device_properties2 or */ \ + /* 1.1 (without KHR suffix) */ \ + OPTIONAL(GetPhysicalDeviceImageFormatProperties2KHR) \ + OPTIONAL(GetPhysicalDeviceFormatProperties2KHR) \ + OPTIONAL(GetPhysicalDeviceFeatures2KHR) \ + /* VK_KHR_device_group + VK_KHR_surface or */ \ + /* 1.1 with VK_KHR_swapchain */ \ + OPTIONAL(GetPhysicalDevicePresentRectanglesKHR) \ + /* VK_KHR_external_fence_capabilities or */ \ + /* 1.1 (without KHR suffix) */ \ + OPTIONAL(GetPhysicalDeviceExternalFencePropertiesKHR) struct instance_dispatch_table { @@ -105,6 +116,7 @@ struct instance_dispatch_table * them automatically to the output of vkEnumeratePhysicalDeviceProperties. */ #define DEVICE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \ + /* Vulkan 1.0 */ \ REQUIRED(GetDeviceProcAddr) \ REQUIRED(GetDeviceQueue) \ REQUIRED(QueueSubmit) \ @@ -129,18 +141,28 @@ struct instance_dispatch_table REQUIRED(ResetFences) \ REQUIRED(WaitForFences) \ REQUIRED(DestroyDevice) \ + /* VK_KHR_swapchain */ \ OPTIONAL(CreateSwapchainKHR) \ OPTIONAL(DestroySwapchainKHR) \ OPTIONAL(GetSwapchainImagesKHR) \ OPTIONAL(AcquireNextImageKHR) \ OPTIONAL(QueuePresentKHR) \ - OPTIONAL(GetMemoryFdPropertiesKHR) \ - OPTIONAL(BindImageMemory2KHR) \ + /* VK_KHR_device_group + VK_KHR_swapchain or */ \ + /* 1.1 with VK_KHR_swapchain */ \ + OPTIONAL(AcquireNextImage2KHR) \ + /* VK_KHR_device_group + VK_KHR_surface or */ \ + /* 1.1 with VK_KHR_swapchain */ \ OPTIONAL(GetDeviceGroupSurfacePresentModesKHR) \ OPTIONAL(GetDeviceGroupPresentCapabilitiesKHR) \ - OPTIONAL(AcquireNextImage2KHR) \ + /* VK_KHR_external_memory_fd */ \ + OPTIONAL(GetMemoryFdPropertiesKHR) \ + /* VK_KHR_bind_memory2 or */ \ + /* 1.1 (without KHR suffix) */ \ + OPTIONAL(BindImageMemory2KHR) \ + /* VK_KHR_external_fence_fd */ \ OPTIONAL(GetFenceFdKHR) \ OPTIONAL(ImportFenceFdKHR) \ + /* VK_KHR_external_semaphore_fd */ \ OPTIONAL(ImportSemaphoreFdKHR) struct device_dispatch_table diff --git a/util/platform_set.hpp b/util/platform_set.hpp index 093975d..5969971 100644 --- a/util/platform_set.hpp +++ b/util/platform_set.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Arm Limited. + * Copyright (c) 2021-2022 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -50,6 +50,11 @@ public: return (m_platforms & (static_cast<uint64_t>(1) << to_int(p))) != 0; } + bool empty() const + { + return m_platforms == 0; + } + private: /** * @brief Convert a VkIcdWsiPlatform to an integer between 0-63. diff --git a/wsi/wsi_factory.cpp b/wsi/wsi_factory.cpp index 0cb2fe5..40d767d 100644 --- a/wsi/wsi_factory.cpp +++ b/wsi/wsi_factory.cpp @@ -150,15 +150,11 @@ VkResult add_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util: { const char *optional_extensions[] = { - VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, - VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, - - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, }; for (auto extension : optional_extensions) |