Support version 7 of the ICD interface. The Vulkan loader requires this version for direct driver loading, which Chromium / Dawn would like to use for loading Swiftshader with the Vulkan loader (so that VVLs can be inserted). - Version 4 adds vk_icdGetPhysicalDeviceProcAddr. - Version 5 adds a check for the apiVersion depending on the negotiated ICD interface version. - Version 6 adds vk_icdEnumerateAdapterPhysicalDevices on Windows (which is a noop for Swiftshader) - Version 7 doesn't require any code change. Bug: dawn:2145 Change-Id: I82cce575662b4b8caf6ba3538f9a954a49eca0bf Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/72488 Tested-by: Corentin Wallez <cwallez@google.com> Commit-Queue: Corentin Wallez <cwallez@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp index d61f600..8a8b759 100644 --- a/src/Vulkan/VkGetProcAddress.cpp +++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -16,6 +16,8 @@ #include "VkDevice.hpp" #include <string> +#include <tuple> +#include <type_traits> #include <unordered_map> #include <vector> @@ -40,17 +42,51 @@ MAKE_VULKAN_GLOBAL_ENTRY(vkEnumerateInstanceExtensionProperties), MAKE_VULKAN_GLOBAL_ENTRY(vkEnumerateInstanceLayerProperties), MAKE_VULKAN_GLOBAL_ENTRY(vkEnumerateInstanceVersion), + + MAKE_VULKAN_GLOBAL_ENTRY(vk_icdGetInstanceProcAddr), + MAKE_VULKAN_GLOBAL_ENTRY(vk_icdNegotiateLoaderICDInterfaceVersion), +#if VK_USE_PLATFORM_WIN32_KHR + MAKE_VULKAN_GLOBAL_ENTRY(vk_icdEnumerateAdapterPhysicalDevices), +#endif // VK_USE_PLATFORM_WIN32_KHR }; #undef MAKE_VULKAN_GLOBAL_ENTRY // Functions that can be obtained through GetInstanceProcAddr with an instance object -#define MAKE_VULKAN_INSTANCE_ENTRY(aFunction) \ - { \ -# aFunction, reinterpret_cast < PFN_vkVoidFunction>(aFunction) \ +struct InstanceFunctionEntry +{ + PFN_vkVoidFunction pfn; + // True if the first argument is a VkPhysicalDevice. See + // https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderDriverInterface.md#reason-for-adding-vk_icdgetphysicaldeviceprocaddr + bool isPhysicalDeviceFn; +}; + +// Template magic to detect if the first argument of a C function is a VkPhysicalDevice. +template<typename T> +struct FunctionArgs +{}; + +template<typename R, typename... Args> +struct FunctionArgs<VKAPI_ATTR R VKAPI_CALL(Args...)> +{ + using Tuple = std::tuple<Args...>; + using FirstType = typename std::tuple_element<0, Tuple>::type; +}; + +template<typename T> +constexpr bool HasPhysicalDeviceFirstArgument = + std::is_same<typename FunctionArgs<T>::FirstType, VkPhysicalDevice>::value; + +#define MAKE_VULKAN_INSTANCE_ENTRY(aFunction) \ + { \ + #aFunction, \ + { \ + reinterpret_cast<PFN_vkVoidFunction>(aFunction), \ + HasPhysicalDeviceFirstArgument<decltype(aFunction)> \ + } \ } // TODO(b/208256248): Avoid exit-time destructor. -static const std::unordered_map<std::string, PFN_vkVoidFunction> instanceFunctionPointers = { +static const std::unordered_map<std::string, InstanceFunctionEntry> instanceFunctionPointers = { MAKE_VULKAN_INSTANCE_ENTRY(vkDestroyInstance), MAKE_VULKAN_INSTANCE_ENTRY(vkEnumeratePhysicalDevices), @@ -652,7 +688,7 @@ auto instanceFunction = instanceFunctionPointers.find(std::string(pName)); if(instanceFunction != instanceFunctionPointers.end()) { - return instanceFunction->second; + return instanceFunction->second.pfn; } auto deviceFunction = deviceFunctionPointers.find(std::string(pName)); @@ -674,6 +710,33 @@ return nullptr; } +PFN_vkVoidFunction GetPhysicalDeviceProcAddr(Instance *instance, const char *pName) +{ + // This function must return nullptr if the name is not known, or the function doesn't take a + // VkPhysicalDevice as the first argument. All functions that have a VkPhysicalDevice as first + // argument are instance function, except for vkGetPhysicalDeviceToolPropertiesEXT which seems + // to have been miscategorized as a device extension when it was made. So we special case that + // funcion. + std::string name = pName; + if(name == "vkGetPhysicalDeviceToolPropertiesEXT") + { + return reinterpret_cast<PFN_vkVoidFunction>(vkGetPhysicalDeviceToolPropertiesEXT); + } + + auto instanceFunction = instanceFunctionPointers.find(name); + if(instanceFunction == instanceFunctionPointers.end()) + { + return nullptr; + } + + if(!instanceFunction->second.isPhysicalDeviceFn) + { + return nullptr; + } + + return instanceFunction->second.pfn; +} + PFN_vkVoidFunction GetDeviceProcAddr(Device *device, const char *pName) { auto deviceFunction = deviceFunctionPointers.find(std::string(pName));
diff --git a/src/Vulkan/VkGetProcAddress.hpp b/src/Vulkan/VkGetProcAddress.hpp index 03c467f..49101ba 100644 --- a/src/Vulkan/VkGetProcAddress.hpp +++ b/src/Vulkan/VkGetProcAddress.hpp
@@ -23,6 +23,7 @@ class Instance; PFN_vkVoidFunction GetInstanceProcAddr(Instance *instance, const char *pName); +PFN_vkVoidFunction GetPhysicalDeviceProcAddr(Instance *instance, const char *pName); PFN_vkVoidFunction GetDeviceProcAddr(Device *device, const char *pName); } // namespace vk
diff --git a/src/Vulkan/android_host_vk_swiftshader.lds b/src/Vulkan/android_host_vk_swiftshader.lds index d9663ed..7318bbb 100644 --- a/src/Vulkan/android_host_vk_swiftshader.lds +++ b/src/Vulkan/android_host_vk_swiftshader.lds
@@ -3,6 +3,7 @@ # Loader-ICD interface functions vk_icdGetInstanceProcAddr; vk_icdNegotiateLoaderICDInterfaceVersion; + vk_icdGetPhysicalDeviceProcAddr; # Vulkan 1.0 API entry functions vkCreateInstance;
diff --git a/src/Vulkan/android_vk_swiftshader.lds b/src/Vulkan/android_vk_swiftshader.lds index be404d9..b88bad3 100644 --- a/src/Vulkan/android_vk_swiftshader.lds +++ b/src/Vulkan/android_vk_swiftshader.lds
@@ -4,6 +4,7 @@ # Loader-ICD interface functions vk_icdGetInstanceProcAddr; vk_icdNegotiateLoaderICDInterfaceVersion; + vk_icdGetPhysicalDeviceProcAddr; # Android HAL module info object HMI;
diff --git a/src/Vulkan/fuchsia_vk_swiftshader.lds b/src/Vulkan/fuchsia_vk_swiftshader.lds index 2237ffb..c4f4464 100644 --- a/src/Vulkan/fuchsia_vk_swiftshader.lds +++ b/src/Vulkan/fuchsia_vk_swiftshader.lds
@@ -6,6 +6,7 @@ # Loader-ICD interface functions vk_icdGetInstanceProcAddr; vk_icdNegotiateLoaderICDInterfaceVersion; + vk_icdGetPhysicalDeviceProcAddr; vk_icdInitializeConnectToServiceCallback; local:
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp index 5360f95..275cf88 100644 --- a/src/Vulkan/libVulkan.cpp +++ b/src/Vulkan/libVulkan.cpp
@@ -96,6 +96,7 @@ #include <algorithm> #include <cinttypes> +#include <cmath> #include <cstring> #include <functional> #include <map> @@ -236,6 +237,11 @@ } } +// This variable will be set to the negotiated ICD interface version negotiated with the loader. +// It defaults to 1 because if vk_icdNegotiateLoaderICDInterfaceVersion is never called it means +// that the loader doens't support version 2 of that interface. +uint32_t sICDInterfaceVersion = 1; + } // namespace extern "C" { @@ -248,10 +254,30 @@ VK_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *pSupportedVersion) { - *pSupportedVersion = 3; + sICDInterfaceVersion = std::min(*pSupportedVersion, 7u); + *pSupportedVersion = sICDInterfaceVersion; return VK_SUCCESS; } +VK_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char *pName) +{ + return vk::GetPhysicalDeviceProcAddr(vk::Cast(instance), pName); +} + +#if VK_USE_PLATFORM_WIN32_KHR + +VKAPI_ATTR VkResult VKAPI_CALL vk_icdEnumerateAdapterPhysicalDevices(VkInstance instance, LUID adapterLUID, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) +{ + if(!pPhysicalDevices) + { + *pPhysicalDeviceCount = 0; + } + + return VK_SUCCESS; +} + +#endif // VK_USE_PLATFORM_WIN32_KHR + #if VK_USE_PLATFORM_FUCHSIA // This symbol must be exported by a Fuchsia Vulkan ICD. The Vulkan loader will @@ -520,6 +546,39 @@ initializeLibrary(); + // ICD interface rule for version 5 of the interface: + // - If the loader supports version 4 or lower, the driver must fail with + // VK_ERROR_INCOMPATIBLE_DRIVER for all vkCreateInstance calls with apiVersion + // set to > Vulkan 1.0 + // - If the loader supports version 5 or above, the loader must fail with + // VK_ERROR_INCOMPATIBLE_DRIVER if it can't handle the apiVersion, and drivers + // should fail with VK_ERROR_INCOMPATIBLE_DRIVER only if they can not support the + // specified apiVersion. + if(pCreateInfo->pApplicationInfo) + { + uint32_t appApiVersion = pCreateInfo->pApplicationInfo->apiVersion; + if(sICDInterfaceVersion <= 4) + { + // Any version above 1.0 is an error. + if(VK_API_VERSION_MAJOR(appApiVersion) != 1 || VK_API_VERSION_MINOR(appApiVersion) != 0) + { + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + } + else + { + if(VK_API_VERSION_MAJOR(appApiVersion) > VK_API_VERSION_MINOR(vk::API_VERSION)) + { + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + if((VK_API_VERSION_MAJOR(appApiVersion) == VK_API_VERSION_MINOR(vk::API_VERSION)) && + VK_API_VERSION_MINOR(appApiVersion) > VK_API_VERSION_MINOR(vk::API_VERSION)) + { + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + } + } + if(pCreateInfo->flags != 0) { // Vulkan 1.3: "flags is reserved for future use." "flags must be 0"
diff --git a/src/Vulkan/vk_swiftshader.def b/src/Vulkan/vk_swiftshader.def index 27354ef..3e3aca4f 100644 --- a/src/Vulkan/vk_swiftshader.def +++ b/src/Vulkan/vk_swiftshader.def
@@ -3,6 +3,8 @@ ; Loader-ICD interface functions vk_icdGetInstanceProcAddr vk_icdNegotiateLoaderICDInterfaceVersion + vk_icdGetPhysicalDeviceProcAddr + vk_icdEnumerateAdapterPhysicalDevices ; Vulkan 1.0 API entry functions vkCreateInstance
diff --git a/src/Vulkan/vk_swiftshader.exports b/src/Vulkan/vk_swiftshader.exports index 1153f00..68819a3 100644 --- a/src/Vulkan/vk_swiftshader.exports +++ b/src/Vulkan/vk_swiftshader.exports
@@ -3,6 +3,7 @@ # Loader-ICD interface functions _vk_icdGetInstanceProcAddr _vk_icdNegotiateLoaderICDInterfaceVersion +_vk_icdGetPhysicalDeviceProcAddr # Type-strings and type-infos required by sanitizers _ZTS*
diff --git a/src/Vulkan/vk_swiftshader.lds b/src/Vulkan/vk_swiftshader.lds index 873e9cd..38ed734 100644 --- a/src/Vulkan/vk_swiftshader.lds +++ b/src/Vulkan/vk_swiftshader.lds
@@ -3,6 +3,7 @@ # Loader-ICD interface functions vk_icdGetInstanceProcAddr; vk_icdNegotiateLoaderICDInterfaceVersion; + vk_icdGetPhysicalDeviceProcAddr; # Vulkan 1.0 API entry functions vkCreateInstance;