From dd1f3f24cc9ecc89ae34c435cf66da8d481af406 Mon Sep 17 00:00:00 2001 From: Matteo Franchin Date: Tue, 17 May 2022 15:18:00 +0100 Subject: 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 --- README.md | 14 ++++--- layer/layer.cpp | 106 ++++++++++++++++++++++++------------------------- layer/private_data.hpp | 68 ++++++++++++++++++++----------- util/platform_set.hpp | 7 +++- wsi/wsi_factory.cpp | 4 -- 5 files changed, 110 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index ec606ee..2d11c69 100644 --- a/README.md +++ b/README.md @@ -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 #include #include +#include #include #include @@ -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 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 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 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 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(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) -- cgit v1.2.3