From 2ced9995dbf7b9cc597f3027b73f2b11187a3fba Mon Sep 17 00:00:00 2001 From: Pete Harris Date: Mon, 13 Jan 2025 22:07:18 +0000 Subject: [PATCH] Workaround pre-instance functions on Android (#53) Pre-instance functions are not supposed to be intercepted, but Android doesn't implement the better interface for chainable pre-instance functions. Trying to use vkGetInstanceProcAddr to get the "next layer down" vkEnumerateInstanceExtensionProperties so a layer can query what extensions are available will not work for any layer other than the bottom layer in the stack. If you have multiple layers in installed, the higher layers will use vkGetInstanceProcAddr to get the function in the next layer down and get the stub implementation for the extensions the layer itself implements without the request reaching the driver. --- source_common/framework/manual_functions.cpp | 33 +++++++++++++++++--- source_common/framework/manual_functions.hpp | 5 +++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/source_common/framework/manual_functions.cpp b/source_common/framework/manual_functions.cpp index e44e72d..bcae148 100644 --- a/source_common/framework/manual_functions.cpp +++ b/source_common/framework/manual_functions.cpp @@ -456,11 +456,30 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateInstance_default( ) { LAYER_TRACE(__func__); - auto* chainInfo = getChainInfo(pCreateInfo); - auto supportedExtensions = getInstanceExtensionList(pCreateInfo); + // We cannot reliably query the available instance extensions on Android if multiple layers are + // installed, so we disable this by default. This occurs because Android only implements the v0 + // specification between the loader and the interceptor, and does not implement chainable + // intercepts for vkEnumerateInstanceExtensionProperties(). + // + // On Android if you call chainInfo getInstanceProcAddr() to get the function in the next layer + // you will get the layer implementation of the function, and layer implementations of this + // function will return the additional extensions that the layer itself provides. It does not + // forward to the driver, and any query for anything other than the layer will just return + // VK_ERROR_LAYER_NOT_PRESENT. + // + // If you are running with a single layer you can set this to true, and use proper queries. + constexpr bool queryExtensions = false; + + std::vector supportedExtensions; + if (queryExtensions) + { + supportedExtensions = getInstanceExtensionList(pCreateInfo); + } + auto* chainInfo = getChainInfo(pCreateInfo); auto fpGetInstanceProcAddr = chainInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr; - auto fpCreateInstance = reinterpret_cast(fpGetInstanceProcAddr(nullptr, "vkCreateInstance")); + auto fpCreateInstanceRaw = fpGetInstanceProcAddr(nullptr, "vkCreateInstance"); + auto fpCreateInstance = reinterpret_cast(fpCreateInstanceRaw); if (!fpCreateInstance) { return VK_ERROR_INITIALIZATION_FAILED; @@ -471,7 +490,13 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateInstance_default( // Query extension state std::string targetExt("VK_EXT_debug_utils"); - bool targetSupported = isIn(targetExt, supportedExtensions); + // Assume common extensions are available (see comment at start of function) + bool targetSupported = true; + if (queryExtensions) + { + targetSupported = isIn(targetExt, supportedExtensions); + } + bool targetEnabled = isInExtensionList( targetExt, pCreateInfo->enabledExtensionCount, diff --git a/source_common/framework/manual_functions.hpp b/source_common/framework/manual_functions.hpp index dcb8760..d66d70c 100644 --- a/source_common/framework/manual_functions.hpp +++ b/source_common/framework/manual_functions.hpp @@ -112,6 +112,11 @@ PFN_vkVoidFunction getDeviceLayerFunction( /** * @brief Fetch the list of supported extensions from the instance. * + * WARNING: This function only works on Android and only works for the bottom + * layer in a stack. Layers higher up the stack are likely to crash, and there + * is no workaround because the the Android loader doesn't implement chainable + * queries for pre-instance functions. + * * @param pCreateInfo The instance creation data from the loader. * * @return The list of supported extensions; empty list on failure.