Make ChainInfo nextGIPA work in vkCreateDevice
authorCharles Giessen <charles@lunarg.com>
Sat, 20 May 2023 21:52:27 +0000 (15:52 -0600)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Mon, 22 May 2023 18:17:19 +0000 (12:17 -0600)
Layers are given chainInfo during instance and device creation. This contains
vkGetInstanceProcAddr (GIPA) that corresponds to the next layer in the chain,
and if there is none, the loader's GIPA terminator. During vkCreateInstance
the instance dispatch table contains the terminators for instance functions.
After vkCreateInstance returns up the call chain, these terminators get
overwritten by calling GIPA on the first layer in the chain.

The problem is that after vkCreateInstance, the instance dispatch table
is being used by loader_gpa_instance_terminator, resulting in the wrong
function being returned to a layer who calls it.

This problem typically only shows up during vkCreateDevice, because the
chainInfo is given to each layer and that chainInfo contains a "nextGIPA".
Except, only the last layer gets a pointer to loader_gpa_instance_terminator,
as every other layer gets the GIPA of the next layer in the chain. Still,
this last layer should not be getting a pointer to the first function in
the chain.

The solution is to stash the terminator dispatch table after returning up
the vkCreateInstance chain but before overwriting the dispatch table with
the first layer in each function chain. Then, inside of
loader_gpa_instance_terminator check if we are still inside of
vkCreateInstance or not.

loader/loader.c
loader/loader_common.h
loader/trampoline.c
tests/framework/layer/wrap_objects.cpp

index 382eb69c88092e8d7181677129ae7c3c1d4e392a..d542cf42fa1ea6bc9fdda4250b18994474086764 100644 (file)
@@ -4239,13 +4239,19 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_terminator(VkInst
     if (inst == VK_NULL_HANDLE) {
         return NULL;
     }
+
     VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
-    void *addr;
 
     if (disp_table == NULL) return NULL;
 
+    struct loader_instance *loader_inst = loader_get_instance(inst);
+
+    if (loader_inst->instance_finished_creation) {
+        disp_table = &loader_inst->terminator_dispatch;
+    }
+
     bool found_name;
-    addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
+    void *addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
     if (found_name) {
         return addr;
     }
@@ -4284,13 +4290,12 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_terminator(VkInstan
     if (inst == VK_NULL_HANDLE) {
         return NULL;
     }
-    struct loader_instance *loader_inst = loader_get_instance(inst);
-
     VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
-    void *addr;
 
     if (disp_table == NULL) return NULL;
 
+    struct loader_instance *loader_inst = loader_get_instance(inst);
+
     // The VK_EXT_debug_utils functions need a special case here so the terminators can still be found from
     // vkGetInstanceProcAddr This is because VK_EXT_debug_utils is an instance level extension with device level functions, and
     // is 'supported' by the loader.
@@ -4329,8 +4334,12 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_terminator(VkInstan
                                                                      : NULL;
     }
 
+    if (loader_inst->instance_finished_creation) {
+        disp_table = &loader_inst->terminator_dispatch;
+    }
+
     bool found_name;
-    addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
+    void *addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
     if (found_name) {
         return addr;
     }
@@ -5017,6 +5026,9 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c
     }
 
     if (res == VK_SUCCESS) {
+        // Copy the current disp table into the terminator_dispatch table so we can use it in loader_gpa_instance_terminator()
+        memcpy(&inst->terminator_dispatch, &inst->disp->layer_inst_disp, sizeof(VkLayerInstanceDispatchTable));
+
         loader_init_instance_core_dispatch_table(&inst->disp->layer_inst_disp, next_gipa, *created_instance);
         inst->instance = *created_instance;
     }
index ebe68c927361ff85e39d44b52e6f7a58c5ed81c2..f3e461a646222920a32e6112eb4bb9a8bc09cdb3 100644 (file)
@@ -235,6 +235,9 @@ struct loader_instance {
     struct loader_instance_dispatch_table *disp;  // must be first entry in structure
     uint64_t magic;                               // Should be LOADER_MAGIC_NUMBER
 
+    // Store all the terminators for instance functions in case a layer queries one *after* vkCreateInstance
+    VkLayerInstanceDispatchTable terminator_dispatch;
+
     // Vulkan API version the app is intending to use.
     loader_api_version app_api_version;
 
@@ -295,6 +298,9 @@ struct loader_instance {
 
     VkAllocationCallbacks alloc_callbacks;
 
+    // Set to true after vkCreateInstance has returned - necessary for loader_gpa_instance_terminator()
+    bool instance_finished_creation;
+
     bool portability_enumeration_enabled;
 
     bool wsi_surface_enabled;
index 944a48be931cc0e4d3c97ed11cb60ff19943152a..f597af835a8b58b22abf834f8da6890b6b26bdab 100644 (file)
@@ -600,6 +600,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCr
         // GetInstanceProcAddr functions to return valid extension functions
         // if enabled.
         loader_activate_instance_layer_extensions(ptr_instance, created_instance);
+        ptr_instance->instance_finished_creation = true;
     } else if (VK_ERROR_EXTENSION_NOT_PRESENT == res && !ptr_instance->create_terminator_invalid_extension) {
         loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0,
                    "vkCreateInstance: Layer returning invalid extension error not triggered by ICD/Loader (Policy #LLP_LAYER_17).");
index f5d920419606a20625a12262e3b1185b4c6ebd10..417714a88b791993794fb67c7737d1b2f6b87faa 100644 (file)
@@ -170,7 +170,7 @@ VKAPI_ATTR VkResult VKAPI_CALL wrap_vkCreateInstance(const VkInstanceCreateInfo
         inst->pfn_inst_init = NULL;
         inst->loader_disp = *(reinterpret_cast<VkLayerInstanceDispatchTable **>(inst->obj));
     }
-    layer_init_instance_dispatch_table(*pInstance, &inst->layer_disp, fpGetInstanceProcAddr);
+    layer_init_instance_dispatch_table(inst->obj, &inst->layer_disp, fpGetInstanceProcAddr);
     bool found = false;
     for (uint32_t layer = 0; layer < pCreateInfo->enabledLayerCount; ++layer) {
         std::string layer_name = pCreateInfo->ppEnabledLayerNames[layer];