Allow layers to call global functions in vkCreateInstance
authorCharles Giessen <charles@lunarg.com>
Thu, 2 May 2024 16:53:19 +0000 (11:53 -0500)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Thu, 2 May 2024 20:34:00 +0000 (14:34 -0600)
Layers that want to call other global functions during vkCreateInstance
couldn't due to loader_gpa_instance_terminator missing the necessary logic.
Because those global functions have a different signature, it was decided
to update the terminator_<function> signatures to match the Vulkan API, and
make dedicated pre-instance intercetpion functions with the appropriate
Chain object as the first parameter.

Now during the call down to vkCreateInstance a layer can query for
pre-instance functions with vkGetInstanceProcAddr and is able to call them
using the Vulkan API function signature.

loader/generated/vk_loader_extensions.h
loader/loader.c
loader/trampoline.c
scripts/loader_extension_generator.py
tests/framework/layer/test_layer.cpp
tests/framework/layer/test_layer.h
tests/loader_layer_tests.cpp

index 66fd83e5bcc2f982fd57f08b5d928a54916da7b6..d81049148979747f0a3600d57618d1364c63fcb9 100644 (file)
@@ -131,6 +131,10 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(
     const VkAllocationCallbacks*                pAllocator,
     VkDevice*                                   pDevice);
 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceExtensionProperties(
+    const char*                                 pLayerName,
+    uint32_t*                                   pPropertyCount,
+    VkExtensionProperties*                      pProperties);
+VKAPI_ATTR VkResult VKAPI_CALL terminator_pre_instance_EnumerateInstanceExtensionProperties(
     const VkEnumerateInstanceExtensionPropertiesChain* chain,
     const char*                                 pLayerName,
     uint32_t*                                   pPropertyCount,
@@ -141,6 +145,9 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(
     uint32_t*                                   pPropertyCount,
     VkExtensionProperties*                      pProperties);
 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceLayerProperties(
+    uint32_t*                                   pPropertyCount,
+    VkLayerProperties*                          pProperties);
+VKAPI_ATTR VkResult VKAPI_CALL terminator_pre_instance_EnumerateInstanceLayerProperties(
     const VkEnumerateInstanceLayerPropertiesChain* chain,
     uint32_t*                                   pPropertyCount,
     VkLayerProperties*                          pProperties);
@@ -158,6 +165,8 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperti
     uint32_t*                                   pPropertyCount,
     VkSparseImageFormatProperties*              pProperties);
 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceVersion(
+    uint32_t*                                   pApiVersion);
+VKAPI_ATTR VkResult VKAPI_CALL terminator_pre_instance_EnumerateInstanceVersion(
     const VkEnumerateInstanceVersionChain* chain,
     uint32_t*                                   pApiVersion);
 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
index a2cef49f278ce836986325cdd1c5769f4f2b79c2..3058b36558ace7e9cc4736e7dc01308d00940561 100644 (file)
@@ -4051,6 +4051,17 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_terminator(VkInstan
     if (!strcmp(pName, "vkCreateInstance")) {
         return (PFN_vkVoidFunction)terminator_CreateInstance;
     }
+    // If a layer is querying pre-instance functions using vkGetInstanceProcAddr, we need to return function pointers that match the
+    // Vulkan API
+    if (!strcmp(pName, "vkEnumerateInstanceLayerProperties")) {
+        return (PFN_vkVoidFunction)terminator_EnumerateInstanceLayerProperties;
+    }
+    if (!strcmp(pName, "vkEnumerateInstanceExtensionProperties")) {
+        return (PFN_vkVoidFunction)terminator_EnumerateInstanceExtensionProperties;
+    }
+    if (!strcmp(pName, "vkEnumerateInstanceVersion")) {
+        return (PFN_vkVoidFunction)terminator_EnumerateInstanceVersion;
+    }
 
     // While the spec is very clear that querying vkCreateDevice requires a valid VkInstance, because the loader allowed querying
     // with a NULL VkInstance handle for a long enough time, it is impractical to fix this bug in the loader
@@ -6772,19 +6783,21 @@ VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
     return result;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceVersion(const VkEnumerateInstanceVersionChain *chain,
-                                                                   uint32_t *pApiVersion) {
-    (void)chain;
+VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceVersion(uint32_t *pApiVersion) {
     // NOTE: The Vulkan WG doesn't want us checking pApiVersion for NULL, but instead
     // prefers us crashing.
     *pApiVersion = VK_HEADER_VERSION_COMPLETE;
     return VK_SUCCESS;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL
-terminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensionPropertiesChain *chain, const char *pLayerName,
-                                                uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
+VKAPI_ATTR VkResult VKAPI_CALL terminator_pre_instance_EnumerateInstanceVersion(const VkEnumerateInstanceVersionChain *chain,
+                                                                                uint32_t *pApiVersion) {
     (void)chain;
+    return terminator_EnumerateInstanceVersion(pApiVersion);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pPropertyCount,
+                                                                               VkExtensionProperties *pProperties) {
     struct loader_extension_list *global_ext_list = NULL;
     struct loader_layer_list instance_layers;
     struct loader_extension_list local_ext_list;
@@ -6879,10 +6892,15 @@ out:
     return res;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceLayerProperties(const VkEnumerateInstanceLayerPropertiesChain *chain,
-                                                                           uint32_t *pPropertyCount,
-                                                                           VkLayerProperties *pProperties) {
+VKAPI_ATTR VkResult VKAPI_CALL terminator_pre_instance_EnumerateInstanceExtensionProperties(
+    const VkEnumerateInstanceExtensionPropertiesChain *chain, const char *pLayerName, uint32_t *pPropertyCount,
+    VkExtensionProperties *pProperties) {
     (void)chain;
+    return terminator_EnumerateInstanceExtensionProperties(pLayerName, pPropertyCount, pProperties);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
+                                                                           VkLayerProperties *pProperties) {
     VkResult result = VK_SUCCESS;
     struct loader_layer_list instance_layer_list;
     struct loader_envvar_all_filters layer_filters = {0};
@@ -6939,6 +6957,12 @@ out:
     return result;
 }
 
+VKAPI_ATTR VkResult VKAPI_CALL terminator_pre_instance_EnumerateInstanceLayerProperties(
+    const VkEnumerateInstanceLayerPropertiesChain *chain, uint32_t *pPropertyCount, VkLayerProperties *pProperties) {
+    (void)chain;
+    return terminator_EnumerateInstanceLayerProperties(pPropertyCount, pProperties);
+}
+
 // ---- Vulkan Core 1.1 terminators
 
 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
index 14766b88ec4c4916141432a80ea69037ca58d635..fec36d89e2d1ee013a9f7cb07df958d49a60adec 100644 (file)
@@ -177,7 +177,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionPropert
                 .version = VK_CURRENT_CHAIN_VERSION,
                 .size = sizeof(chain_tail),
             },
-        .pfnNextLayer = &terminator_EnumerateInstanceExtensionProperties,
+        .pfnNextLayer = &terminator_pre_instance_EnumerateInstanceExtensionProperties,
         .pNextLink = NULL,
     };
     VkEnumerateInstanceExtensionPropertiesChain *chain_head = &chain_tail;
@@ -283,7 +283,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(
                 .version = VK_CURRENT_CHAIN_VERSION,
                 .size = sizeof(chain_tail),
             },
-        .pfnNextLayer = &terminator_EnumerateInstanceLayerProperties,
+        .pfnNextLayer = &terminator_pre_instance_EnumerateInstanceLayerProperties,
         .pNextLink = NULL,
     };
     VkEnumerateInstanceLayerPropertiesChain *chain_head = &chain_tail;
@@ -396,7 +396,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion(uint32_t
                 .version = VK_CURRENT_CHAIN_VERSION,
                 .size = sizeof(chain_tail),
             },
-        .pfnNextLayer = &terminator_EnumerateInstanceVersion,
+        .pfnNextLayer = &terminator_pre_instance_EnumerateInstanceVersion,
         .pNextLink = NULL,
     };
     VkEnumerateInstanceVersionChain *chain_head = &chain_tail;
index 58413042e122c0670a380f0299fcc9b2aba2a8f7..1df98f4000a0b1438b6906b7a87c13cfac93709a 100644 (file)
@@ -799,15 +799,21 @@ class LoaderExtensionOutputGenerator(OutputGenerator):
                 mod_string = new_terminator.replace("VKAPI_CALL vk", "VKAPI_CALL terminator_")
 
                 if cur_cmd.name in PRE_INSTANCE_FUNCTIONS:
+                    pre_instance_basic_version = mod_string
+                    mod_string = mod_string.replace("terminator_", "terminator_pre_instance_")
                     mod_string = mod_string.replace(cur_cmd.name[2:] + '(\n', cur_cmd.name[2:] + '(\n    const Vk' + cur_cmd.name[2:] + 'Chain* chain,\n')
 
-                if (cur_cmd.protect is not None):
+                if cur_cmd.protect is not None:
                     terminators += '#if defined(%s)\n' % cur_cmd.protect
 
+                if cur_cmd.name in PRE_INSTANCE_FUNCTIONS:
+                    terminators += pre_instance_basic_version
+                    terminators += '\n'
+
                 terminators += mod_string
                 terminators += '\n'
 
-                if (cur_cmd.protect is not None):
+                if cur_cmd.protect is not None:
                     terminators += '#endif // %s\n' % cur_cmd.protect
 
         terminators += '\n'
index 4fca974df98570fde7638640870dbc0ae7d7fdb1..93c27c73cee4fb5a793b7be5204605b114fbf46d 100644 (file)
@@ -280,6 +280,37 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateInstance(const VkInstanceCreateInfo*
     if (layer.clobber_pInstance) {
         memset(*pInstance, 0, 128);
     }
+    PFN_vkEnumerateInstanceLayerProperties fpEnumerateInstanceLayerProperties{};
+    PFN_vkEnumerateInstanceExtensionProperties fpEnumerateInstanceExtensionProperties{};
+    PFN_vkEnumerateInstanceVersion fpEnumerateInstanceVersion{};
+
+    if (layer.query_vkEnumerateInstanceLayerProperties) {
+        fpEnumerateInstanceLayerProperties = reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
+            fpGetInstanceProcAddr(nullptr, "vkEnumerateInstanceLayerProperties"));
+        uint32_t count = 0;
+        fpEnumerateInstanceLayerProperties(&count, nullptr);
+        if (count == 0) return VK_ERROR_LAYER_NOT_PRESENT;
+        std::vector<VkLayerProperties> layers{count, VkLayerProperties{}};
+        fpEnumerateInstanceLayerProperties(&count, layers.data());
+        if (count == 0) return VK_ERROR_LAYER_NOT_PRESENT;
+    }
+    if (layer.query_vkEnumerateInstanceExtensionProperties) {
+        fpEnumerateInstanceExtensionProperties = reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
+            fpGetInstanceProcAddr(nullptr, "vkEnumerateInstanceExtensionProperties"));
+        uint32_t count = 0;
+        fpEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
+        if (count == 0) return VK_ERROR_LAYER_NOT_PRESENT;
+        std::vector<VkExtensionProperties> extensions{count, VkExtensionProperties{}};
+        fpEnumerateInstanceExtensionProperties(nullptr, &count, extensions.data());
+        if (count == 0) return VK_ERROR_LAYER_NOT_PRESENT;
+    }
+    if (layer.query_vkEnumerateInstanceVersion) {
+        fpEnumerateInstanceVersion =
+            reinterpret_cast<PFN_vkEnumerateInstanceVersion>(fpGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion"));
+        uint32_t version = 0;
+        fpEnumerateInstanceVersion(&version);
+        if (version == 0) return VK_ERROR_LAYER_NOT_PRESENT;
+    }
 
     // Continue call down the chain
     VkResult result = fpCreateInstance(create_info_pointer, pAllocator, pInstance);
index d6d086c14d2fa688e7bd6402e5579905bbac72dc..322bf9e0de01a6040314af10ad0ed5e6d3143cb7 100644 (file)
@@ -195,6 +195,10 @@ struct TestLayer {
     // Clober the data pointed to by pDevice to overwrite the magic value
     BUILDER_VALUE(TestLayer, bool, clobber_pDevice, false)
 
+    BUILDER_VALUE(TestLayer, bool, query_vkEnumerateInstanceLayerProperties, false)
+    BUILDER_VALUE(TestLayer, bool, query_vkEnumerateInstanceExtensionProperties, false)
+    BUILDER_VALUE(TestLayer, bool, query_vkEnumerateInstanceVersion, false)
+
     PFN_vkGetInstanceProcAddr next_vkGetInstanceProcAddr = VK_NULL_HANDLE;
     PFN_GetPhysicalDeviceProcAddr next_GetPhysicalDeviceProcAddr = VK_NULL_HANDLE;
     PFN_vkGetDeviceProcAddr next_vkGetDeviceProcAddr = VK_NULL_HANDLE;
index 01ead76e75d109c483a919a4cfa3b8714eda6a08..762865e4e3ca1edcd5138f20d103b770030e159a 100644 (file)
@@ -2011,6 +2011,29 @@ TEST(ExplicitLayers, ContainsPreInstanceFunctions) {
     ASSERT_TRUE(string_eq(layers.at(0).layerName, explicit_layer_name));
 }
 
+TEST(ExplicitLayers, CallsPreInstanceFunctionsInCreateInstance) {
+    FrameworkEnvironment env;
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
+    const char* explicit_layer_name = "VK_LAYER_enabled_by_override";
+
+    env.add_explicit_layer(
+        ManifestLayer{}.set_file_format_version({1, 1, 2}).add_layer(
+            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+        "explicit_test_layer.json");
+
+    auto& layer = env.get_test_layer(0);
+    layer.set_query_vkEnumerateInstanceLayerProperties(true);
+    layer.set_query_vkEnumerateInstanceExtensionProperties(true);
+    layer.set_query_vkEnumerateInstanceVersion(true);
+
+    InstWrapper inst{env.vulkan_functions};
+    inst.create_info.add_layer(explicit_layer_name);
+    inst.CheckCreate();
+
+    auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
+    ASSERT_TRUE(string_eq(layers.at(0).layerName, explicit_layer_name));
+}
+
 // This test makes sure that any layer calling GetPhysicalDeviceProperties2 inside of CreateInstance
 // succeeds and doesn't crash.
 TEST(LayerCreateInstance, GetPhysicalDeviceProperties2) {