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;