diff --git a/source_common/framework/manual_functions.cpp b/source_common/framework/manual_functions.cpp index 05f93e4..196a1a1 100644 --- a/source_common/framework/manual_functions.cpp +++ b/source_common/framework/manual_functions.cpp @@ -111,17 +111,38 @@ VkLayerDeviceCreateInfo* getChainInfo(const VkDeviceCreateInfo* pCreateInfo) } /* See header for documentation. */ -PFN_vkVoidFunction getInstanceLayerFunction(const char* name) +std::pair getInstanceLayerFunction(const char* name) { + const std::array globalFunctions { + // Supported since Vulkan 1.0 + "vkCreateInstance", + "vkEnumerateInstanceExtensionProperties", + "vkEnumerateInstanceLayerProperties", + // Supported since Vulkan 1.1 + "vkEnumerateInstanceVersion", + // Supported since Vulkan 1.2 + "vkGetInstanceProcAddr", + }; + + bool isGlobal {false}; + for (const auto* globalName : globalFunctions) + { + if (!strcmp(globalName, name)) + { + isGlobal = true; + break; + } + } + for (auto& function : instanceIntercepts) { if (!strcmp(function.name, name)) { - return function.function; + return {isGlobal, function.function}; } } - return nullptr; + return {isGlobal, nullptr}; } /* See header for documentation. */ @@ -147,12 +168,14 @@ APIVersion getInstanceAPIVersion(PFN_vkGetInstanceProcAddr fpGetProcAddr) return { 1, 3 }; #endif + // Try to get vkEnumerateInstanceVersion, and assume this is a Vulkan 1.0 + // feature level if we don't get it ... auto fpFunctionRaw = fpGetProcAddr(nullptr, "vkEnumerateInstanceVersion"); auto fpFunction = reinterpret_cast(fpFunctionRaw); if (!fpFunction) { - LAYER_ERR("Failed to get vkEnumerateInstanceVersion()"); - return {0, 0}; + LAYER_ERR("Failed to get vkEnumerateInstanceVersion(), assuming Vulkan 1.0"); + return {1, 0}; } uint32_t apiVersion = 0; @@ -474,9 +497,18 @@ void enableDeviceVkExtImageCompressionControl(Instance& instance, /** See Vulkan API for documentation. */ PFN_vkVoidFunction layer_vkGetInstanceProcAddr_default(VkInstance instance, const char* pName) { - // Only expose functions that the driver exposes to avoid changing - // queryable interface behavior seen by the application - auto layerFunction = getInstanceLayerFunction(pName); + auto [isGlobal, layerFunction] = getInstanceLayerFunction(pName); + + // Global functions must be exposed and do not require the caller to pass + // a valid instance pointer, although it is required to be nullptr in + // Vulkan 1.2.193 or later + if (isGlobal) + { + return layerFunction; + } + + // For other functions, only expose functions that the driver exposes to + // avoid changing queryable interface behavior seen by the application if (instance) { std::unique_lock lock {g_vulkanLock}; diff --git a/source_common/framework/manual_functions.hpp b/source_common/framework/manual_functions.hpp index 8240cc2..6854c58 100644 --- a/source_common/framework/manual_functions.hpp +++ b/source_common/framework/manual_functions.hpp @@ -44,6 +44,7 @@ #include #include #include +#include #include /** @@ -85,10 +86,11 @@ PFN_vkVoidFunction getFixedInstanceLayerFunction(const char* name); * * @param name The Vulkan function name. * - * @return The layer function pointer, or \c nullptr if the layer doesn't + * @return Boolean indicating if this is a globally accessible function, and + * the layer function pointer, or \c nullptr if the layer doesn't * intercept the function. */ -PFN_vkVoidFunction getInstanceLayerFunction(const char* name); +std::pair getInstanceLayerFunction(const char* name); /** * @brief Fetch the function for a given dynamic instance entrypoint name.