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>
This commit is contained in:
Matteo Franchin 2022-05-17 15:18:00 +01:00
parent 2bc2109194
commit dd1f3f24cc
5 changed files with 118 additions and 97 deletions

View file

@ -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. `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 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 The ICDs installed in the system are required to support the following extensions:
later API, and the following device extensions: * Instance extensions:
* When Wayland support is enabled: * 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_EXT_image_drm_format_modifier
* VK_KHR_image_format_list * VK_KHR_image_format_list
* VK_EXT_external_memory_dma_buf * VK_EXT_external_memory_dma_buf
* VK_KHR_external_memory_fd * VK_KHR_external_memory_fd
* VK_KHR_external_fence_fd * VK_KHR_external_fence_fd
* Any dependencies of the above extensions
### Building the Vulkan® loader ### 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` linear formats. This is selected by the `-DSELECT_EXTERNAL_ALLOCATOR=ion`
option, as shown above. 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 ## Installation
Copy the shared library `libVkLayer_window_system_integration.so` and JSON Copy the shared library `libVkLayer_window_system_integration.so` and JSON

View file

@ -25,6 +25,7 @@
#include <cassert> #include <cassert>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <array>
#include <vulkan/vk_layer.h> #include <vulkan/vk_layer.h>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
@ -102,45 +103,58 @@ VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, con
return VK_ERROR_INITIALIZATION_FAILED; 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<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())
{
/* 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<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();
}
/* Advance the link info for the next element on the chain. */ /* Advance the link info for the next element on the chain. */
layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext; 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. /* 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. * 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. * 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. * Also, the loader filters the extension list to ensure that ICDs do not see extensions that they do not support.
*/ */
VkResult result; TRY(fpCreateInstance(&modified_info, pAllocator, pInstance));
result = fpCreateInstance(&modified_info, pAllocator, pInstance);
if (result != VK_SUCCESS)
{
return result;
}
instance_dispatch_table table{}; instance_dispatch_table table{};
VkResult result;
result = table.populate(*pInstance, fpGetInstanceProcAddr); result = table.populate(*pInstance, fpGetInstanceProcAddr);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
@ -151,9 +165,6 @@ VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, con
return result; 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, /* Following the spec: use the callbacks provided to vkCreateInstance() if not nullptr,
* otherwise use the default callbacks. * 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. */ /* Advance the link info for the next element on the chain. */
layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext; 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); auto &inst_data = instance_private_data::get(physicalDevice);
util::allocator allocator{inst_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, pAllocator}; 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<const char *> modified_enabled_extensions{allocator}; util::vector<const char *> modified_enabled_extensions{allocator};
result = enabled_extensions.get_extension_strings(modified_enabled_extensions); util::extension_list enabled_extensions{allocator};
if (result != VK_SUCCESS)
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. */ /* Now call create device on the chain further down the list. */
VkDeviceCreateInfo modified_info = *pCreateInfo; TRY(fpCreateDevice(physicalDevice, &modified_info, pAllocator, pDevice));
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;
}
device_dispatch_table table{}; device_dispatch_table table{};
result = table.populate(*pDevice, fpGetDeviceProcAddr); VkResult result = table.populate(*pDevice, fpGetDeviceProcAddr);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
if (table.DestroyDevice != nullptr) if (table.DestroyDevice != nullptr)

View file

@ -57,25 +57,36 @@ namespace layer
* fails if vkGetInstanceProcAddr returns null for entrypoints that are REQUIRED(). * fails if vkGetInstanceProcAddr returns null for entrypoints that are REQUIRED().
*/ */
#define INSTANCE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \ #define INSTANCE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \
/* Vulkan 1.0 */ \
REQUIRED(GetInstanceProcAddr) \ REQUIRED(GetInstanceProcAddr) \
REQUIRED(DestroyInstance) \ REQUIRED(DestroyInstance) \
REQUIRED(GetPhysicalDeviceProperties) \ REQUIRED(GetPhysicalDeviceProperties) \
REQUIRED(GetPhysicalDeviceImageFormatProperties) \ REQUIRED(GetPhysicalDeviceImageFormatProperties) \
REQUIRED(EnumerateDeviceExtensionProperties) \ REQUIRED(EnumerateDeviceExtensionProperties) \
/* VK_KHR_surface */ \
OPTIONAL(DestroySurfaceKHR) \
OPTIONAL(GetPhysicalDeviceSurfaceCapabilitiesKHR) \ OPTIONAL(GetPhysicalDeviceSurfaceCapabilitiesKHR) \
OPTIONAL(GetPhysicalDeviceSurfaceCapabilities2KHR) \
OPTIONAL(GetPhysicalDeviceSurfaceFormatsKHR) \ OPTIONAL(GetPhysicalDeviceSurfaceFormatsKHR) \
OPTIONAL(GetPhysicalDeviceSurfaceFormats2KHR) \
OPTIONAL(GetPhysicalDeviceSurfacePresentModesKHR) \ OPTIONAL(GetPhysicalDeviceSurfacePresentModesKHR) \
OPTIONAL(GetPhysicalDeviceSurfaceSupportKHR) \ OPTIONAL(GetPhysicalDeviceSurfaceSupportKHR) \
/* VK_EXT_headless_surface */ \
OPTIONAL(CreateHeadlessSurfaceEXT) \ OPTIONAL(CreateHeadlessSurfaceEXT) \
/* VK_KHR_wayland_surface */ \
OPTIONAL(CreateWaylandSurfaceKHR) \ OPTIONAL(CreateWaylandSurfaceKHR) \
OPTIONAL(DestroySurfaceKHR) \ /* VK_KHR_get_surface_capabilities2 */ \
OPTIONAL(GetPhysicalDeviceSurfaceCapabilities2KHR) \
OPTIONAL(GetPhysicalDeviceSurfaceFormats2KHR) \
/* VK_KHR_get_physical_device_properties2 or */ \
/* 1.1 (without KHR suffix) */ \
OPTIONAL(GetPhysicalDeviceImageFormatProperties2KHR) \ OPTIONAL(GetPhysicalDeviceImageFormatProperties2KHR) \
OPTIONAL(GetPhysicalDeviceFormatProperties2KHR) \ OPTIONAL(GetPhysicalDeviceFormatProperties2KHR) \
OPTIONAL(GetPhysicalDeviceFeatures2KHR) \
/* VK_KHR_device_group + VK_KHR_surface or */ \
/* 1.1 with VK_KHR_swapchain */ \
OPTIONAL(GetPhysicalDevicePresentRectanglesKHR) \ OPTIONAL(GetPhysicalDevicePresentRectanglesKHR) \
OPTIONAL(GetPhysicalDeviceExternalFencePropertiesKHR)\ /* VK_KHR_external_fence_capabilities or */ \
OPTIONAL(GetPhysicalDeviceFeatures2KHR) /* 1.1 (without KHR suffix) */ \
OPTIONAL(GetPhysicalDeviceExternalFencePropertiesKHR)
struct instance_dispatch_table struct instance_dispatch_table
{ {
@ -105,6 +116,7 @@ struct instance_dispatch_table
* them automatically to the output of vkEnumeratePhysicalDeviceProperties. * them automatically to the output of vkEnumeratePhysicalDeviceProperties.
*/ */
#define DEVICE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \ #define DEVICE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \
/* Vulkan 1.0 */ \
REQUIRED(GetDeviceProcAddr) \ REQUIRED(GetDeviceProcAddr) \
REQUIRED(GetDeviceQueue) \ REQUIRED(GetDeviceQueue) \
REQUIRED(QueueSubmit) \ REQUIRED(QueueSubmit) \
@ -129,18 +141,28 @@ struct instance_dispatch_table
REQUIRED(ResetFences) \ REQUIRED(ResetFences) \
REQUIRED(WaitForFences) \ REQUIRED(WaitForFences) \
REQUIRED(DestroyDevice) \ REQUIRED(DestroyDevice) \
/* VK_KHR_swapchain */ \
OPTIONAL(CreateSwapchainKHR) \ OPTIONAL(CreateSwapchainKHR) \
OPTIONAL(DestroySwapchainKHR) \ OPTIONAL(DestroySwapchainKHR) \
OPTIONAL(GetSwapchainImagesKHR) \ OPTIONAL(GetSwapchainImagesKHR) \
OPTIONAL(AcquireNextImageKHR) \ OPTIONAL(AcquireNextImageKHR) \
OPTIONAL(QueuePresentKHR) \ OPTIONAL(QueuePresentKHR) \
OPTIONAL(GetMemoryFdPropertiesKHR) \ /* VK_KHR_device_group + VK_KHR_swapchain or */ \
OPTIONAL(BindImageMemory2KHR) \ /* 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(GetDeviceGroupSurfacePresentModesKHR) \
OPTIONAL(GetDeviceGroupPresentCapabilitiesKHR) \ 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(GetFenceFdKHR) \
OPTIONAL(ImportFenceFdKHR) \ OPTIONAL(ImportFenceFdKHR) \
/* VK_KHR_external_semaphore_fd */ \
OPTIONAL(ImportSemaphoreFdKHR) OPTIONAL(ImportSemaphoreFdKHR)
struct device_dispatch_table struct device_dispatch_table

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Arm Limited. * Copyright (c) 2021-2022 Arm Limited.
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
* *
@ -50,6 +50,11 @@ public:
return (m_platforms & (static_cast<uint64_t>(1) << to_int(p))) != 0; return (m_platforms & (static_cast<uint64_t>(1) << to_int(p))) != 0;
} }
bool empty() const
{
return m_platforms == 0;
}
private: private:
/** /**
* @brief Convert a VkIcdWsiPlatform to an integer between 0-63. * @brief Convert a VkIcdWsiPlatform to an integer between 0-63.

View file

@ -150,15 +150,11 @@ VkResult add_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util:
{ {
const char *optional_extensions[] = const char *optional_extensions[] =
{ {
VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME,
VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME,
VK_KHR_EXTERNAL_FENCE_FD_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_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
}; };
for (auto extension : optional_extensions) for (auto extension : optional_extensions)