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; } + /* For instances handled by the layer, we need to enable extra extensions, therefore take a copy of pCreateInfo. */ + VkInstanceCreateInfo modified_info = *pCreateInfo; + + /* 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. + */ + 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()) + { + /* 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)) + { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + /* 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(); + } + /* Advance the link info for the next element on the chain. */ layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext; - /* 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. - */ - const uint32_t minimum_required_vulkan_version = VK_API_VERSION_1_1; - VkApplicationInfo modified_app_info{}; - if (nullptr != pCreateInfo->pApplicationInfo) - { - modified_app_info = *pCreateInfo->pApplicationInfo; - if (modified_app_info.apiVersion < minimum_required_vulkan_version) - { - modified_app_info.apiVersion = minimum_required_vulkan_version; - } - } - else - { - modified_app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - modified_app_info.apiVersion = minimum_required_vulkan_version; - } - - VkInstanceCreateInfo modified_info = *pCreateInfo; - modified_info.pApplicationInfo = &modified_app_info; - /* 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. */ + /* 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::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) - { - return result; - } - util::vector modified_enabled_extensions{allocator}; - result = enabled_extensions.get_extension_strings(modified_enabled_extensions); - if (result != VK_SUCCESS) + util::extension_list enabled_extensions{allocator}; + + const util::wsi_platform_set& enabled_platforms = inst_data.get_enabled_platforms(); + 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)); + + 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)