From 4a6f61a72b098e0d33f995da0c424bfbfd8602d1 Mon Sep 17 00:00:00 2001 From: Maged Elnaggar Date: Fri, 27 Jun 2025 15:21:58 +0000 Subject: [PATCH] This commit merges several related changes to make the layer fully spec-compliant and avoid leaking unsupported symbols. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extension enablement * Only enable extensions promoted to core in Vulkan 1.1 when the application’s API version is < 1.1. * Filter the list passed to vkGet{Instance,Device}ProcAddr so that only _application_-enabled extensions affect symbol lookup. Internally-added extensions are ignored during GetProcAddr resolution. Entrypoint exposure fixes * getProcAddr now only returns pointers for entrypoints when _all_ of their required extensions (or core version) are enabled: * vkGetPhysicalDevicePresentRectanglesKHR * vkAcquireNextImage2KHR * vkGetDeviceGroupSurfacePresentModesKHR * vkBindImageMemory2 / vkBindImageMemory2KHR * vkGetPhysicalDeviceFeatures2KHR * Removed all OR-conditions that previously exposed these functions prematurely, replacing them with clear AND-checks per the spec. Always-exposed device-level entrypoints * Introduce INSTANCE_ENTRYPOINTS_LIST_EXPANSION for entrypoints that: * Come from device-level extensions, * Are looked up via instance APIs, * Are _not_ in core Vulkan. * Assign them an empty extension string so they’re always exposed, regardless of which instance extensions the application requests. Hiding non-intercepted functions * Any entrypoint the layer lists internally but does _not_ intercept is now hidden from applications, preventing calls into stubs. These combined changes ensure the layer: * advertises only the extensions it needs, * obeys all cross-extension dependencies, and * never leaks unsupported symbols via GetInstanceProcAddr/GetDeviceProcAddr. Signed-off-by: Maged Elnaggar maged.elnaggar@arm.com Change-Id: I7a5e5cb210e017f1aed76b187db1f40537010914 --- layer/layer.cpp | 133 ++++++++++++++++++++-------- layer/private_data.cpp | 64 +++++-------- layer/private_data.hpp | 29 ++++-- wsi/display/surface_properties.cpp | 39 ++++++-- wsi/display/surface_properties.hpp | 4 +- wsi/headless/surface_properties.cpp | 21 +++-- wsi/headless/surface_properties.hpp | 2 +- wsi/surface_properties.hpp | 6 +- wsi/wayland/surface_properties.cpp | 61 ++++++++----- wsi/wayland/surface_properties.hpp | 4 +- wsi/wsi_factory.cpp | 9 +- wsi/wsi_factory.hpp | 8 +- 12 files changed, 241 insertions(+), 139 deletions(-) diff --git a/layer/layer.cpp b/layer/layer.cpp index f59d985..3ad9bef 100644 --- a/layer/layer.cpp +++ b/layer/layer.cpp @@ -143,13 +143,16 @@ VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, con /* Create a list of extensions to enable, including the provided extensions and those required by the layer. */ TRY_LOG_CALL(extensions.add(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount)); + uint32_t api_version = + pCreateInfo->pApplicationInfo != nullptr ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_3; + if (!layer_platforms_to_enable.empty()) { if (!extensions.contains(VK_KHR_SURFACE_EXTENSION_NAME)) { return VK_ERROR_EXTENSION_NOT_PRESENT; } - TRY_LOG_CALL(wsi::add_instance_extensions_required_by_layer(layer_platforms_to_enable, extensions)); + TRY_LOG_CALL(wsi::add_instance_extensions_required_by_layer(layer_platforms_to_enable, extensions, api_version)); } TRY_LOG_CALL(extensions.get_extension_strings(modified_enabled_extensions)); @@ -181,9 +184,6 @@ VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, con return VK_ERROR_OUT_OF_HOST_MEMORY; } - uint32_t api_version = - pCreateInfo->pApplicationInfo != nullptr ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_3; - TRY_LOG_CALL(table->populate(*pInstance, fpGetInstanceProcAddr, api_version)); table->set_user_enabled_extensions(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount); @@ -196,7 +196,7 @@ VKAPI_ATTR VkResult create_instance(const VkInstanceCreateInfo *pCreateInfo, con */ VkResult result = instance_private_data::get(*pInstance) - .set_instance_enabled_extensions(modified_enabled_extensions.data(), modified_enabled_extensions.size()); + .set_instance_enabled_extensions(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount); if (result != VK_SUCCESS) { instance_private_data::disassociate(*pInstance); @@ -249,7 +249,8 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic if (!enabled_platforms.empty()) { TRY_LOG_CALL(enabled_extensions.add(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->enabledExtensionCount)); - TRY_LOG_CALL(wsi::add_device_extensions_required_by_layer(physicalDevice, enabled_platforms, enabled_extensions)); + TRY_LOG_CALL(wsi::add_device_extensions_required_by_layer(physicalDevice, enabled_platforms, enabled_extensions, + inst_data.api_version)); TRY_LOG_CALL(enabled_extensions.get_extension_strings(modified_enabled_extensions)); modified_info.ppEnabledExtensionNames = modified_enabled_extensions.data(); @@ -339,8 +340,8 @@ VKAPI_ATTR VkResult create_device(VkPhysicalDevice physicalDevice, const VkDevic auto &device_data = layer::device_private_data::get(*pDevice); device_data.set_layer_frame_boundary_handling_enabled(should_layer_handle_frame_boundary_events); - result = device_data.set_device_enabled_extensions(modified_info.ppEnabledExtensionNames, - modified_info.enabledExtensionCount); + result = device_data.set_device_enabled_extensions(pCreateInfo->ppEnabledExtensionNames, + pCreateInfo->enabledExtensionCount); if (result != VK_SUCCESS) { layer::device_private_data::disassociate(*pDevice); @@ -476,8 +477,8 @@ VWL_VKAPI_EXPORT wsi_layer_vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLay } VWL_VKAPI_CALL(void) -wsi_layer_vkGetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physical_device, - VkPhysicalDeviceFeatures2 *pFeatures) VWL_API_POST +wsi_layer_vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physical_device, + VkPhysicalDeviceFeatures2 *pFeatures) VWL_API_POST { auto &instance = layer::instance_private_data::get(physical_device); @@ -555,68 +556,114 @@ wsi_layer_vkGetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physical_device, if (!strcmp(funcName, #func)) \ return (PFN_vkVoidFunction)&wsi_layer_##func; +/** + * @brief Trampoline for **vkGetDeviceProcAddr** inside the WSI layer. + * + * Workflow: + * 1. Retrieve the device’s private state (enabled extensions and downstream dispatch table). + * 2. If the function is one that this layer intercepts, return the layer’s handler. + * 3. Otherwise, forward to the downstream dispatch table (next layer or ICD), or return nullptr if unavailable. + * + * This layer never exposes entrypoints for disabled extensions, preserving the Vulkan dispatch-chain contract. + * + * @param device The VkDevice being queried. + * @param funcName Name of the device-level command to resolve. + * @return Pointer to the layer’s implementation, the next-layer/ICD function, or nullptr. + */ VWL_VKAPI_CALL(PFN_vkVoidFunction) wsi_layer_vkGetDeviceProcAddr(VkDevice device, const char *funcName) VWL_API_POST { - uint64_t api_version = layer::device_private_data::get(device).instance_data.api_version; - if (layer::device_private_data::get(device).is_device_extension_enabled(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) + auto &device_data = layer::device_private_data::get(device); + const uint64_t api_version = device_data.instance_data.api_version; + const bool core_1_1 = api_version >= VK_API_VERSION_1_1; + if (device_data.is_device_extension_enabled(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { GET_PROC_ADDR(vkCreateSwapchainKHR); GET_PROC_ADDR(vkDestroySwapchainKHR); GET_PROC_ADDR(vkGetSwapchainImagesKHR); GET_PROC_ADDR(vkAcquireNextImageKHR); GET_PROC_ADDR(vkQueuePresentKHR); - GET_PROC_ADDR(vkAcquireNextImage2KHR); - GET_PROC_ADDR(vkGetDeviceGroupPresentCapabilitiesKHR); - GET_PROC_ADDR(vkGetDeviceGroupSurfacePresentModesKHR); + if (device_data.is_device_extension_enabled(VK_KHR_DEVICE_GROUP_EXTENSION_NAME) || core_1_1) + { + GET_PROC_ADDR(vkAcquireNextImage2KHR); + } + if (core_1_1) + { + GET_PROC_ADDR(vkGetDeviceGroupSurfacePresentModesKHR); + GET_PROC_ADDR(vkGetDeviceGroupPresentCapabilitiesKHR); + } } - if (layer::device_private_data::get(device).is_device_extension_enabled( - VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME)) + + if (device_data.is_device_extension_enabled(VK_KHR_DEVICE_GROUP_EXTENSION_NAME) && + device_data.is_device_extension_enabled(VK_KHR_SURFACE_EXTENSION_NAME)) + { + GET_PROC_ADDR(vkGetDeviceGroupSurfacePresentModesKHR); + GET_PROC_ADDR(vkGetDeviceGroupPresentCapabilitiesKHR); + } + + if (device_data.is_device_extension_enabled(VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME)) { GET_PROC_ADDR(vkGetSwapchainStatusKHR); } #if VULKAN_WSI_LAYER_EXPERIMENTAL - if (layer::device_private_data::get(device).is_device_extension_enabled(VK_EXT_PRESENT_TIMING_EXTENSION_NAME)) + if (device_data.is_device_extension_enabled(VK_EXT_PRESENT_TIMING_EXTENSION_NAME)) { GET_PROC_ADDR(vkSetSwapchainPresentTimingQueueSizeEXT); GET_PROC_ADDR(vkGetSwapchainTimingPropertiesEXT); GET_PROC_ADDR(vkGetSwapchainTimeDomainPropertiesEXT); GET_PROC_ADDR(vkGetPastPresentationTimingEXT); GET_PROC_ADDR(vkGetCalibratedTimestampsKHR); - if (layer::device_private_data::get(device).is_device_extension_enabled( - VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME)) + if (device_data.is_device_extension_enabled(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME)) { GET_PROC_ADDR(vkGetCalibratedTimestampsEXT); } } #endif GET_PROC_ADDR(vkDestroyDevice); - GET_PROC_ADDR(vkCreateImage); - GET_PROC_ADDR(vkBindImageMemory2); - if (!strcmp(funcName, "vkBindImageMemory2KHR") && - layer::device_private_data::get(device).disp.get_user_enabled_entrypoint(device, api_version, funcName) != - nullptr) + if (device_data.is_device_extension_enabled(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME)) { - return (PFN_vkVoidFunction)&wsi_layer_vkBindImageMemory2; + if (!strcmp(funcName, "vkBindImageMemory2KHR")) + { + return (PFN_vkVoidFunction)&wsi_layer_vkBindImageMemory2; + } + } + if (core_1_1) + { + GET_PROC_ADDR(vkBindImageMemory2); } /* VK_EXT_swapchain_maintenance1 */ - if (layer::device_private_data::get(device).is_device_extension_enabled( - VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME)) + if (device_data.is_device_extension_enabled(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME)) { GET_PROC_ADDR(vkReleaseSwapchainImagesEXT); } - if (layer::device_private_data::get(device).is_device_extension_enabled(VK_KHR_PRESENT_WAIT_EXTENSION_NAME)) + if (device_data.is_device_extension_enabled(VK_KHR_PRESENT_WAIT_EXTENSION_NAME)) { GET_PROC_ADDR(vkWaitForPresentKHR); } - return layer::device_private_data::get(device).disp.get_user_enabled_entrypoint( - device, layer::device_private_data::get(device).instance_data.api_version, funcName); + return device_data.disp.get_user_enabled_entrypoint(device, funcName); } +/** + * @brief Trampoline for **vkGetInstanceProcAddr** inside the WSI layer. + * + * Workflow: + * 1. Publish loader-critical symbols (i.e. `vkGetDeviceProcAddr`, `vkGetInstanceProcAddr`). + * 2. Retrieve the instance’s private state (API version and enabled extensions) + * and intercept layer-handled commands. + * 3. Forward all other commands to the downstream instance dispatch table, + * or return nullptr if unavailable. + * + * This layer only exposes core commands and enabled-extension entrypoints, + * preserving the Vulkan dispatch-chain contract. + * + * @param instance The VkInstance being queried (may be VK_NULL_HANDLE). + * @param funcName Name of the instance-level command to resolve. + * @return Pointer to this layer’s handler, the next-layer/ICD function, or nullptr. + */ VWL_VKAPI_CALL(PFN_vkVoidFunction) wsi_layer_vkGetInstanceProcAddr(VkInstance instance, const char *funcName) VWL_API_POST { @@ -625,18 +672,26 @@ wsi_layer_vkGetInstanceProcAddr(VkInstance instance, const char *funcName) VWL_A GET_PROC_ADDR(vkCreateInstance); GET_PROC_ADDR(vkDestroyInstance); GET_PROC_ADDR(vkCreateDevice); - GET_PROC_ADDR(vkGetPhysicalDevicePresentRectanglesKHR); - - if (!strcmp(funcName, "vkGetPhysicalDeviceFeatures2")) - { - return (PFN_vkVoidFunction)wsi_layer_vkGetPhysicalDeviceFeatures2KHR; - } auto &instance_data = layer::instance_private_data::get(instance); + const bool core_1_1 = instance_data.api_version >= VK_API_VERSION_1_1; + if ((instance_data.is_instance_extension_enabled(VK_KHR_DEVICE_GROUP_EXTENSION_NAME) && + instance_data.is_instance_extension_enabled(VK_KHR_SURFACE_EXTENSION_NAME)) || + core_1_1) + { + GET_PROC_ADDR(vkGetPhysicalDevicePresentRectanglesKHR); + } if (instance_data.is_instance_extension_enabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { - GET_PROC_ADDR(vkGetPhysicalDeviceFeatures2KHR); + if (!strcmp(funcName, "vkGetPhysicalDeviceFeatures2KHR")) + { + return (PFN_vkVoidFunction)&wsi_layer_vkGetPhysicalDeviceFeatures2; + } + } + if (core_1_1) + { + GET_PROC_ADDR(vkGetPhysicalDeviceFeatures2); } if (instance_data.is_instance_extension_enabled(VK_KHR_SURFACE_EXTENSION_NAME)) @@ -660,5 +715,5 @@ wsi_layer_vkGetInstanceProcAddr(VkInstance instance, const char *funcName) VWL_A } } - return instance_data.disp.get_user_enabled_entrypoint(instance, instance_data.api_version, funcName); + return instance_data.disp.get_user_enabled_entrypoint(instance, funcName); } diff --git a/layer/private_data.cpp b/layer/private_data.cpp index 0248da3..f9b57bf 100644 --- a/layer/private_data.cpp +++ b/layer/private_data.cpp @@ -98,23 +98,29 @@ void dispatch_table::set_user_enabled_extensions(const char *const *extension_na } } -PFN_vkVoidFunction instance_dispatch_table::get_user_enabled_entrypoint(VkInstance instance, uint32_t api_version, - const char *fn_name) const +/** + * @brief Decide whether we should expose this Vulkan entrypoint to the application. + * + * An entrypoint is exposable if any of the following are true: + * - The application explicitly enabled its extension/command. + * - It’s part of core Vulkan 1.0. + * - It has no associated extension name (`ep.ext_name` is empty), e.g. + * `vkGetPhysicalDeviceCalibrateableTimeDomainsKHR` + * + * @param[in] ep The entrypoint metadata to evaluate. + * @return `true` if the layer should expose this entrypoint, `false` otherwise. + */ +static inline bool should_expose_entrypoint(const entrypoint &ep) { - auto item = m_entrypoints->find(fn_name); - if (item != m_entrypoints->end()) + return ep.user_visible || (ep.api_version == VK_API_VERSION_1_0) || (ep.ext_name && ep.ext_name[0] == '\0'); +} + +PFN_vkVoidFunction instance_dispatch_table::get_user_enabled_entrypoint(VkInstance instance, const char *fn_name) const +{ + auto itr = m_entrypoints->find(fn_name); + if (itr != m_entrypoints->end()) { - /* An entrypoint is allowed to use if it has been enabled by the user or is included in the core specficiation of the API version. - * Entrypoints included in API version 1.0 are allowed by default. */ - if (item->second.user_visible || item->second.api_version <= api_version || - item->second.api_version == VK_API_VERSION_1_0) - { - return item->second.fn; - } - else - { - return nullptr; - } + return should_expose_entrypoint(itr->second) ? itr->second.fn : nullptr; } return GetInstanceProcAddr(instance, fn_name).value_or(nullptr); @@ -159,36 +165,12 @@ VkResult device_dispatch_table::populate(VkDevice dev, PFN_vkGetDeviceProcAddr g return VK_SUCCESS; } -PFN_vkVoidFunction device_dispatch_table::get_user_enabled_entrypoint(VkDevice device, uint32_t api_version, - const char *fn_name) const +PFN_vkVoidFunction device_dispatch_table::get_user_enabled_entrypoint(VkDevice device, const char *fn_name) const { auto itr = m_entrypoints->find(fn_name); if (itr != m_entrypoints->end()) { - /* An entrypoint is allowed to be used: - * - if it has been enabled by the user, - * - or if is included in the core specficiation of the API version. - * Entrypoints included in API version 1.0 are allowed by default. - */ - const entrypoint &ep = itr->second; - - if (ep.user_visible) - { - return ep.fn; - } - - if (ep.api_version == VK_API_VERSION_1_0) - { - return ep.fn; - } - - bool is_core = (ep.ext_name != nullptr && ep.ext_name[0] == '\0'); - if (is_core && ep.api_version <= api_version) - { - return ep.fn; - } - - return nullptr; + return should_expose_entrypoint(itr->second) ? itr->second.fn : nullptr; } return GetDeviceProcAddr(device, fn_name).value_or(nullptr); diff --git a/layer/private_data.hpp b/layer/private_data.hpp index 6a0ad02..cb61dab 100644 --- a/layer/private_data.hpp +++ b/layer/private_data.hpp @@ -277,9 +277,24 @@ static constexpr uint32_t API_VERSION_MAX = UINT32_MAX; EP(SetDebugUtilsObjectNameEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME, API_VERSION_MAX, false, ) \ EP(SetDebugUtilsObjectTagEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME, API_VERSION_MAX, false, ) \ EP(SubmitDebugUtilsMessageEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME, API_VERSION_MAX, false, ) \ - /* VK_KHR_calibrated_timestamps */ \ - EP(GetPhysicalDeviceCalibrateableTimeDomainsKHR, VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, API_VERSION_MAX, \ - false, ) + /* Custom entrypoints */ \ + INSTANCE_ENTRYPOINTS_LIST_EXPANSION(EP) + +/* + * Extension list for INSTANCE_ENTRYPOINTS_LIST containing entrypoints that: + * - Are not part of core Vulkan, + * - Belong to device-level extensions, + * - Are queried via instance-level APIs. + * + * These entrypoints have an empty extension name ("") to ensure they are + * always exposed, regardless of extension enablement, as their use does not + * depend on any specific instance extension being advertised. + */ +#define INSTANCE_ENTRYPOINTS_LIST_EXPANSION(EP) \ + /* VK_KHR_calibrated_timestamps */ \ + EP(GetPhysicalDeviceCalibrateableTimeDomainsKHR, "", API_VERSION_MAX, false, ) \ + /* VK_EXT_calibrated_timestamps */ \ + EP(GetPhysicalDeviceCalibrateableTimeDomainsEXT, "", API_VERSION_MAX, false, ) /** * @brief Struct representing the instance dispatch table. @@ -314,11 +329,10 @@ public: * @brief Get the user enabled instance extension entrypoint by name * * @param instance The Vulkan instance that the extension was enabled on. - * @param api_version The API version of the Vulkan instance. * @param fn_name The name of the function. * @return pointer to the function if it is enabled by the user, otherwise nullptr. */ - PFN_vkVoidFunction get_user_enabled_entrypoint(VkInstance instance, uint32_t api_version, const char *fn_name) const; + PFN_vkVoidFunction get_user_enabled_entrypoint(VkInstance instance, const char *fn_name) const; /* Generate alias functions for internal use of the dispatch table entrypoints. * These will be named as the entrypoint, but without the "vk" prefix. @@ -455,7 +469,7 @@ private: EP(GetBufferMemoryRequirements2KHR, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_API_VERSION_1_1, false, \ GetBufferMemoryRequirements2) \ EP(GetImageSparseMemoryRequirements2KHR, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_API_VERSION_1_1, \ - false, GetImageSparseMemoryRequirements2KHR) \ + false, GetImageSparseMemoryRequirements2) \ /* VK_EXT_swapchain_maintenance1 */ \ EP(ReleaseSwapchainImagesEXT, VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, VK_API_VERSION_1_1, false, ) \ /* VK_EXT_calibrated_timestamps */ \ @@ -500,11 +514,10 @@ public: * @brief Get the user enabled device extension entrypoint by name * * @param device The Vulkan device that the extension was enabled on. - * @param api_version The API version of the Vulkan instance. * @param fn_name The name of the function. * @return pointer to the function if it is enabled by the user, otherwise nullptr. */ - PFN_vkVoidFunction get_user_enabled_entrypoint(VkDevice device, uint32_t api_version, const char *fn_name) const; + PFN_vkVoidFunction get_user_enabled_entrypoint(VkDevice device, const char *fn_name) const; /* Generate alias functions for internal use of the dispatch table entrypoints. * These will be named as the entrypoint, but without the "vk" prefix. diff --git a/wsi/display/surface_properties.cpp b/wsi/display/surface_properties.cpp index 9582e24..339bfdf 100644 --- a/wsi/display/surface_properties.cpp +++ b/wsi/display/surface_properties.cpp @@ -507,23 +507,44 @@ PFN_vkVoidFunction surface_properties::get_proc_addr(const char *name) return nullptr; } -VkResult surface_properties::get_required_instance_extensions(util::extension_list &extension_list) +VkResult surface_properties::get_required_instance_extensions(util::extension_list &extension_list, + const uint32_t api_version) { - const std::array required_instance_extensions{ - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, - }; - - return extension_list.add(required_instance_extensions.data(), required_instance_extensions.size()); + VkResult result = VK_SUCCESS; + /* Enable extensions that were promoted to core in Vulkan 1.1 when using API versions < 1.1 */ + if (api_version < VK_API_VERSION_1_1) + { + const std::array required_extensions_pre_vulkan_1_1{ + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + }; + result = extension_list.add(required_extensions_pre_vulkan_1_1.data(), required_extensions_pre_vulkan_1_1.size()); + } + return result; } -VkResult surface_properties::get_required_device_extensions(util::extension_list &extension_list) +VkResult surface_properties::get_required_device_extensions(util::extension_list &extension_list, + const uint32_t api_version) { + VkResult result = VK_SUCCESS; const std::array required_device_extensions{ VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, - VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, }; + result = extension_list.add(required_device_extensions.data(), required_device_extensions.size()); + if (result != VK_SUCCESS) + { + return result; + } - return extension_list.add(required_device_extensions.data(), required_device_extensions.size()); + /* Enable extensions that were promoted to core in Vulkan 1.1 when using API versions < 1.1 */ + if (api_version < VK_API_VERSION_1_1) + { + const std::array required_extensions_pre_vulkan_1_1{ + VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, + }; + result = extension_list.add(required_extensions_pre_vulkan_1_1.data(), required_extensions_pre_vulkan_1_1.size()); + } + + return result; } bool surface_properties::is_surface_extension_enabled(const layer::instance_private_data &instance_data) diff --git a/wsi/display/surface_properties.hpp b/wsi/display/surface_properties.hpp index 0ec31b4..13cd705 100644 --- a/wsi/display/surface_properties.hpp +++ b/wsi/display/surface_properties.hpp @@ -60,9 +60,9 @@ public: PFN_vkVoidFunction get_proc_addr(const char *name) override; - VkResult get_required_instance_extensions(util::extension_list &extension_list) override; + VkResult get_required_instance_extensions(util::extension_list &extension_list, const uint32_t api_version) override; - VkResult get_required_device_extensions(util::extension_list &extension_list) override; + VkResult get_required_device_extensions(util::extension_list &extension_list, const uint32_t api_version) override; bool is_surface_extension_enabled(const layer::instance_private_data &instance_data) override; diff --git a/wsi/headless/surface_properties.cpp b/wsi/headless/surface_properties.cpp index 1cb0198..578397d 100644 --- a/wsi/headless/surface_properties.cpp +++ b/wsi/headless/surface_properties.cpp @@ -191,14 +191,21 @@ PFN_vkVoidFunction surface_properties::get_proc_addr(const char *name) return nullptr; } -VkResult surface_properties::get_required_instance_extensions(util::extension_list &extension_list) +VkResult surface_properties::get_required_instance_extensions(util::extension_list &extension_list, + const uint32_t api_version) { - const std::array required_instance_extensions{ - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, - VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, - VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, - }; - return extension_list.add(required_instance_extensions.data(), required_instance_extensions.size()); + VkResult result = VK_SUCCESS; + /* Enable extensions that were promoted to core in Vulkan 1.1 when using API versions < 1.1 */ + if (api_version < VK_API_VERSION_1_1) + { + const std::array required_extensions_pre_vulkan_1_1{ + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, + }; + result = extension_list.add(required_extensions_pre_vulkan_1_1.data(), required_extensions_pre_vulkan_1_1.size()); + } + return result; } bool surface_properties::is_surface_extension_enabled(const layer::instance_private_data &instance_data) diff --git a/wsi/headless/surface_properties.hpp b/wsi/headless/surface_properties.hpp index 35a2cc4..5d530ec 100644 --- a/wsi/headless/surface_properties.hpp +++ b/wsi/headless/surface_properties.hpp @@ -56,7 +56,7 @@ public: PFN_vkVoidFunction get_proc_addr(const char *name) override; - VkResult get_required_instance_extensions(util::extension_list &extension_list) override; + VkResult get_required_instance_extensions(util::extension_list &extension_list, const uint32_t api_version) override; bool is_surface_extension_enabled(const layer::instance_private_data &instance_data) override; diff --git a/wsi/surface_properties.hpp b/wsi/surface_properties.hpp index 59301ca..bd1a0ab 100644 --- a/wsi/surface_properties.hpp +++ b/wsi/surface_properties.hpp @@ -78,17 +78,19 @@ public: /** * @brief Return the device extensions that this surface_properties implementation needs. */ - virtual VkResult get_required_device_extensions(util::extension_list &extension_list) + virtual VkResult get_required_device_extensions(util::extension_list &extension_list, const uint32_t api_version) { /* Requires no additional extensions */ UNUSED(extension_list); + UNUSED(api_version); return VK_SUCCESS; } /** * @brief Return the instance extensions that this surface_properties implementation needs. */ - virtual VkResult get_required_instance_extensions(util::extension_list &extension_list) = 0; + virtual VkResult get_required_instance_extensions(util::extension_list &extension_list, + const uint32_t api_version) = 0; /** * @brief Implements vkGetProcAddr for entrypoints specific to the surface type. diff --git a/wsi/wayland/surface_properties.cpp b/wsi/wayland/surface_properties.cpp index 7c33960..7fe3a93 100644 --- a/wsi/wayland/surface_properties.cpp +++ b/wsi/wayland/surface_properties.cpp @@ -251,34 +251,51 @@ VkResult surface_properties::get_surface_present_modes(VkPhysicalDevice physical return get_surface_present_modes_common(pPresentModeCount, pPresentModes, m_supported_modes); } -VkResult surface_properties::get_required_device_extensions(util::extension_list &extension_list) +VkResult surface_properties::get_required_device_extensions(util::extension_list &extension_list, + const uint32_t api_version) { + VkResult result = VK_SUCCESS; const std::array required_device_extensions{ - VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, - VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, - VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, - VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, - VK_KHR_MAINTENANCE1_EXTENSION_NAME, - VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, - VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, - VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, - VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, - VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, - VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, - VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, + VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, + VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, + VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, }; - return extension_list.add(required_device_extensions.data(), required_device_extensions.size()); + result = extension_list.add(required_device_extensions.data(), required_device_extensions.size()); + if (result != VK_SUCCESS) + { + return result; + } + + /* Enable extensions that were promoted to core in Vulkan 1.1 when using API versions < 1.1 */ + if (api_version < VK_API_VERSION_1_1) + { + const std::array required_extensions_pre_vulkan_1_1{ + VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, + VK_KHR_MAINTENANCE1_EXTENSION_NAME, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, + VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME + }; + result = extension_list.add(required_extensions_pre_vulkan_1_1.data(), required_extensions_pre_vulkan_1_1.size()); + } + + return result; } -VkResult surface_properties::get_required_instance_extensions(util::extension_list &extension_list) +VkResult surface_properties::get_required_instance_extensions(util::extension_list &extension_list, + const uint32_t api_version) { - const std::array required_instance_extensions{ - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, - VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, - VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, - VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, - }; - return extension_list.add(required_instance_extensions.data(), required_instance_extensions.size()); + VkResult result = VK_SUCCESS; + /* Enable extensions that were promoted to core in Vulkan 1.1 when using API versions < 1.1 */ + if (api_version < VK_API_VERSION_1_1) + { + const std::array required_extensions_pre_vulkan_1_1{ + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, + }; + result = extension_list.add(required_extensions_pre_vulkan_1_1.data(), required_extensions_pre_vulkan_1_1.size()); + } + return result; } struct required_properties diff --git a/wsi/wayland/surface_properties.hpp b/wsi/wayland/surface_properties.hpp index 1d604c6..9d7af1d 100644 --- a/wsi/wayland/surface_properties.hpp +++ b/wsi/wayland/surface_properties.hpp @@ -65,9 +65,9 @@ public: VkResult get_surface_present_modes(VkPhysicalDevice physical_device, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) override; - VkResult get_required_device_extensions(util::extension_list &extension_list) override; + VkResult get_required_device_extensions(util::extension_list &extension_list, const uint32_t api_version) override; - VkResult get_required_instance_extensions(util::extension_list &extension_list) override; + VkResult get_required_instance_extensions(util::extension_list &extension_list, const uint32_t api_version) override; PFN_vkVoidFunction get_proc_addr(const char *name) override; diff --git a/wsi/wsi_factory.cpp b/wsi/wsi_factory.cpp index 915e98a..1ba7197 100644 --- a/wsi/wsi_factory.cpp +++ b/wsi/wsi_factory.cpp @@ -153,7 +153,7 @@ static VkResult get_available_device_extensions(VkPhysicalDevice physical_device VkResult add_device_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util::wsi_platform_set enabled_platforms, - util::extension_list &extensions_to_enable) + util::extension_list &extensions_to_enable, const uint32_t api_version) { util::allocator allocator{ extensions_to_enable.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND }; @@ -198,7 +198,7 @@ VkResult add_device_extensions_required_by_layer(VkPhysicalDevice phys_dev, return VK_ERROR_INITIALIZATION_FAILED; } - TRY_LOG(props->get_required_device_extensions(extensions_required_by_layer), + TRY_LOG(props->get_required_device_extensions(extensions_required_by_layer, api_version), "Failed to acquire required device extensions"); bool supported = available_device_extensions.contains(extensions_required_by_layer); @@ -219,7 +219,8 @@ VkResult add_device_extensions_required_by_layer(VkPhysicalDevice phys_dev, } VkResult add_instance_extensions_required_by_layer(const util::wsi_platform_set enabled_platforms, - util::extension_list &extensions_to_enable) + util::extension_list &extensions_to_enable, + const uint32_t api_version) { util::allocator allocator{ extensions_to_enable.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND }; /* Requesting available instance extensions (as it happens with the device) @@ -241,7 +242,7 @@ VkResult add_instance_extensions_required_by_layer(const util::wsi_platform_set return VK_ERROR_INITIALIZATION_FAILED; } - TRY_LOG(props->get_required_instance_extensions(extensions_required_by_layer), + TRY_LOG(props->get_required_instance_extensions(extensions_required_by_layer, api_version), "Failed to acquire required instance extensions"); TRY_LOG_CALL(extensions_to_enable.add(extensions_required_by_layer)); diff --git a/wsi/wsi_factory.hpp b/wsi/wsi_factory.hpp index bedbe09..3ded9d6 100644 --- a/wsi/wsi_factory.hpp +++ b/wsi/wsi_factory.hpp @@ -92,23 +92,27 @@ util::wsi_platform_set find_enabled_layer_platforms(const VkInstanceCreateInfo * * @param[in] phys_dev The physical device to check. * @param[in] enabled_platforms All the platforms that the layer must enable for @p phys_dev. * @param[in,out] extensions_to_enable All the extensions required by the layer are added to this list. + * @param[in] api_version The Vulkan API version being used. * * @retval @c VK_SUCCESS if the operation was successful. */ VkResult add_device_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util::wsi_platform_set enabled_platforms, - util::extension_list &extensions_to_enable); + util::extension_list &extensions_to_enable, + const uint32_t api_version); /** * @brief Add required instance extensions by the layer. * * @param[in] enabled_platforms All the enabled platforms for the current instance. * @param[in,out] extensions_to_enable All the extensions required by the layer are added to this list. + * @param[in] api_version The Vulkan API version being used. * * @retval @c VK_SUCCESS if the operation was successful. */ VkResult add_instance_extensions_required_by_layer(const util::wsi_platform_set enabled_platforms, - util::extension_list &extensions_to_enable); + util::extension_list &extensions_to_enable, + const uint32_t api_version); /** * @brief Return a function pointer for surface specific functions.